2011-05-21 11 views
5

Necesito crear un proxy que intercepte propiedades en una clase. Sé cómo crear un proxy dinámico con Emit desde una interfaz, pero ¿qué sucede si no tengo una interfaz? He visto muestras que usan RealProxy (como esta: Is there a way to call a method when any property of a class is set?), pero ¿es posible usar generación de tipo y emitir para lograr lo mismo? No quiero que el "propietario" de la clase concreta vea ningún rastro de MarshalByRefObject si es posible (ver abajo) ...¿Genera un proxy de interceptación de una clase concreta?

Creo que Castle puede hacer esto, pero ¿tal vez está usando RealProxy bajo las sábanas?

User user = Create<User>(); 

public class User 
{ 
    public string Name { get; set; } 
} 

public T Create<T>() 
{ 
    //magic happens here... :) 
    return (T)GenerateInterceptingProxyFromT(typeof(T)); 
} 

Respuesta

0

Acabo de empezar a jugar con postshrp, una de las herramientas de AOP que mencionó Miguel, hacer funcionalmente lo que estás tratando de hacer. Utiliza el "tejido estático" para inyectar código en tiempo de compilación, por lo que debe ser invisible para los consumidores. Obviamente, necesita modificar el código que desea instrumentar para que esto funcione.
La respuesta a This question sugiere utilizar la API de perfil que puede ser una opción para usted si PostSharp o Castle no hace lo que necesita.

+0

Como esa pregunta que sugirió, parece que la API profiler es la única forma de hacerlo, a menos que use algún tipo de cosa post-AOP, que soy no puede usar en este caso, lamentablemente. –

0

Hay algunas opciones en la interceptación de las cosas en .Net:

  • Si se trata de una interfaz, se puede implementar un nuevo tipo de esa dinámica, y hacer un proxy, que sería re- llama al otro objeto interno.

  • Si se trata de una clase abstracta o una clase que permite sustituciones, puede heredar de ella y anular dinámicamente los miembros deseados y hacer lo que desee.

  • Si el tipo que desea interceptar no tiene interfaces, métodos ni propiedades, entonces debe cambiar el ensamblaje que constate ese tipo, antes de que se cargue. No puede cambiar el código de un conjunto después de que se haya cargado. Creo que PostSharp funciona de esta manera.

La mayoría de las herramientas burlones, usados ​​para propósitos de prueba utiliza la primera, segunda alternativas /, pero que hace que funcionen únicamente con miembros de las clases que son reemplazable, o puesto en práctica a través de una interfaz.

La programación orientada a aspectos utiliza la tercera alternativa, pero es más trabajo por hacer, porque debe procesar el conjunto antes de que se cargue.

+0

No tengo una interfaz, y la clase no es abstracta y no tiene propiedades virtuales. Vea la muestra de clase de usuario anterior. Tal vez es imposible? Creo que necesito investigar cómo Castle DynamicProxy hace las cosas :) –

0

Dado que este es un problema muy común y una gran razón para elegir un enfoque AOP como sugirió Miguel, I created an example para Afterthought que demuestra la implementación de INotifyPropertyChanged (interceptar conjuntos de propiedades para generar un evento).

La idea de último momento le permite describir las interceptaciones de propiedades muy fácilmente, y hace que la interceptación del conjunto de propiedades sea simple al proporcionarle los valores de antes y después de la propiedad.Se podría hacer algo como esto para identificar las propiedades de interceptar:

public override void Amend<TProperty>(Property<TProperty> property) 
{ 
    // Raise property change notifications 
    if (property.PropertyInfo.CanRead && property.PropertyInfo.CanWrite) 
     property.AfterSet = NotificationAmender<T>.OnPropertyChanged<TProperty>; 
} 

que en este caso llama a un método estático OnPropertyChanged que se parece a esto:

public static void OnPropertyChanged<P>(INotifyPropertyChangedAmendment instance, string property, P oldValue, P value, P newValue) 
{ 
    // Only raise property changed if the value of the property actually changed 
    if ((oldValue == null^newValue == null) || (oldValue != null && !oldValue.Equals(newValue))) 
     instance.OnPropertyChanged(new PropertyChangedEventArgs(property)); 
} 

Así que si su propiedad original era la siguiente:

string name; 
public string Name 
{ 
    get 
    { 
     return name; 
    } 
    set 
    { 
     name = value; 
    } 
} 

Se vería así después de la aplicación de la enmienda anterior utilizando Afterthought:

string name; 
public string Name 
{ 
    get 
    { 
     return name; 
    } 
    set 
    { 
     string oldValue = Name; 
     name = value; 
     NotificationAmender<ConcreteClass>.OnPropertyChanged<string>(
      this, "Name", oldValue, value, Name); 
    } 
} 

En su caso, el método estático llamado después (o antes) del colocador podría nombrarse como desee y hacer lo que quiera. Este es solo un ejemplo de una razón concreta y bien conocida para interceptar los emisores de propiedades. Dado que usted sabe que las propiedades no son virtuales, no es posible crear subclases de proxy para realizar la interceptación, por lo que creo que los enfoques de AOP como Afterthought o PostSharp son su mejor opción.

Además, con la última idea puede implementar la interceptación de modo que los ensamblados resultantes no tengan referencias o dependencias en Pensamiento posterior y si su lógica de interceptación no agrega ni cambia la API para sus tipos de destino, no hay razón para "propietario" de la clase concreta tendría un problema con el resultado.

Cuestiones relacionadas