2011-05-17 13 views
30

Tanto en Ruby como en PHP (y supongo que en otros idiomas también) hay algunos métodos de utilidad que se llaman cada vez que se establece una propiedad. (* instance_variable_set * para Ruby, * __ set * para PHP).¿Hay alguna manera de interceptar setters y getters en C#?

tanto, vamos a decir que tengo una clase C# como esto:

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

Ahora, vamos a decir que si cualquier colocador propiedad de la clase Person se llama, quiero llamar a otro método en primer lugar, y luego continuar con el comportamiento predeterminado del colocador, y lo mismo aplica para los establecedores de propiedades.

¿Esto es posible?


Editar: quiero hacer esto sin definir un campo de respaldo.

+0

El método que muestra ahora implementa un campo de respaldo en MSIL de todos modos, entonces ¿por qué no quiere uno? – Mr47

+0

@ Mr47 Claro, pero no quiero definirlo yo mismo. Quiero una forma automática de hacer esto. –

+2

Me temo que cualquier otra forma será más engorrosa que solo tener un campo de respaldo. – Mr47

Respuesta

28

En general; algunas opciones sin embargo;

  • Heredar del ContextBoundObject - el cual qué permitir esto, pero a un rendimiento de costes
  • escribir una propiedad explícita (es decir, con un campo de respaldo), y añadir un método de utilidad llamada manualmente
  • vistazo a la compilación -time weavers, como PostSharp - generalmente detectando un atributo o similar
  • mira los generadores de código de tiempo de ejecución, como se ofrecen con algunas herramientas DI/IoC (y algunas otras herramientas basadas en decorador) que decoran o subclasifican tu objeto para agregar el código adicional
+0

¿Puede proporcionar un enlace que muestre cómo hacerlo a través de 'ContextBoundObject'? Gracias. –

+0

Creo que 'DynamicObject' también se puede usar en este caso (anulando' TrySetMember'). Pero, ¿cómo puede 'ContextBoundObject'? –

+0

@Danny - en última instancia, las propiedades son métodos - así que algo como esto debería funcionar: http://www.codeproject.com/KB/cs/aspectintercept.aspx –

4

Deberá escribir las propiedades completas para lograr esto.

1

No fuera de la caja. Debería insertar el código en cada setter y getter de propiedades, ya sea de forma manual o automática utilizando la reescritura IL.

Cuando quiera hacerlo manualmente, ya no podrá usar propiedades automáticas.
Cuando quiera hacerlo automáticamente, eche un vistazo a AOP.

14

Es posible hacerlo directamente en el cuerpo de la propiedad en sí, pero luego debe usar un campo de respaldo adecuado en lugar de auto-implemented properties.

private string firstName; 

public string FirstName 
{ 
    get { return firstName;} 
    set 
    { 
    if(check(value)) 
    { 
     firstName = value; 
    } 
    } 
} 

Incluso con propiedades implementadas automáticamente se obtiene una materia respaldo - esto es generada por el compilador y que no tienen acceso directo a la misma.


Editar:

En vista de que no desea que un campo de respaldo, que tienen otras opciones - con ayuda de una herramienta AOP como PostSharp podrían ayudar con eso.

1

Sí, por supuesto ...

En su ejemplo está utilizando propiedades automáticas, sin un campo de respaldo .... Solo necesita crear un campo de respaldo para su propiedad, y luego puede hacer lo que desee en el colocador y el absorbente.

ejemplo:

private string firstName; 

public string FirstName 
{ 
get { return firstName; } 

set { doMethod(); firstName = value;} 
} 
0

Por lo que yo sé, usted tiene que utilizar un campo de respaldo y poner la llamada al otro método dentro de la incubadora de esta manera:

public class Person { 
    private string firstName; 
    private string lastName; 

    public string FirstName { 
     set { 
      DoSomeStuff(); 
      firstName = value; 
     } 
     get { return firstName; } 
    } 

    public string LastName { 
     set { 
      DoSomeStuff(); 
      lastName = value; 
     } 
     get { return lastName; } 
    } 
} 
1

marcos que imita pueden hacer esto, así como las bibliotecas de IoC como Unity. La única otra forma de hacer tal cosa sería usar IL-reescritura (como se mencionó anteriormente).

1

No puede usar las propiedades automáticas. Tendría que cambiar la propiedad a la vieja usanza con un campo de respaldo y llamar al método manualmente.

public class Person 
{ 
    private string _FirstName; 
    public string FirstName 
    { 
     get 
     { 
      return _FirstName; 
     } 
     set 
     { 
      SomeMethod(); 
      _FirstName = value; 
     } 
    } 
    private void SomeMethod() 
    { 
     //do something 
    } 

} 
2

Sé que esto ha sido debidamente contestadas, pero voy a incluir un ejemplo para mostrar la sintaxis para lograr lo que quiere:

public class Person 
{ 
    private 
    public string FirstName 
    { 
     get 
     { 
      return _firstName; 
     } 
     set 
     { 
      // see how we can call a method below? or any code for that matter.. 
      _firstName = SanitizeName(value); 
     } 
    } 
} 
2

¿Está en condiciones de volver a escribir su clase para implementar una interfaz? Si es así, Unity's interface interceptor podría darle lo que necesita. Si una interfaz no es una opción, ese enlace también documenta los interceptores tipo e instancia de Unity.

0

Sí, puede usar el patrón de diseño del decorador.

Cuestiones relacionadas