2008-11-14 8 views
13

Teniendo en cuenta la clase siguiente:¿Hay un delegado disponible para las propiedades en C#?

class TestClass { 
    public void SetValue(int value) { Value = value; } 
    public int Value { get; set; } 
} 

que puedo hacer

TestClass tc = new TestClass(); 
Action<int> setAction = tc.SetValue; 
setAction.Invoke(12); 

que está todo bien. ¿Es posible hacer lo mismo usando la propiedad en lugar del método? Preferiblemente con algo incorporado a .net.

Respuesta

21

Se puede crear el delegado utilizando la reflexión:

Action<int> valueSetter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), tc, tc.GetType().GetProperty("Value").GetSetMethod()); 

o crear un delegado a un método anónimo, que establece la propiedad;

Action<int> valueSetter = v => tc.Value = v; 

Editar: se ha usado una sobrecarga incorrecta para CreateDelegate(), necesita usar la que toma y el objeto como destino. Fijo.

+0

Creo que esto funcionará para las necesidades que tengo. ¡Gracias! –

+0

Dado que se supone que C# es mi primer idioma, realmente me gustaría entender esto (crear un delegado usando la reflexión) - suena genial – JohnIdol

+1

Y para .net 2.0 se podría hacer Acción valueSetter = delegate (int value) {tc .Value = valor; } –

3

Las propiedades son realmente envolturas alrededor de métodos en .Net, por lo que el uso de la reflexión que debe ser capaz de obtener el delegado (set_property y GET_PROPERTY) y luego ejecutarlos ...

Ver System.Reflection.PropertyInfo

Si tiene dos métodos que puede usar para obtener/establecer el valor: GetGetMethod y GetSetMethod.

por lo que podría escribir:

var propertyInfo = typeof (TestClass).GetProperty ("Value"); 

var setMethod = property.GetSetMethod(); // This will return a MethodInfo class. 
+2

Aunque la especificación C# reserva los métodos get_P y set_P para cualquier propiedad P, no es necesario que las implementaciones utilicen estos métodos para las propiedades. Esto lo convierte en un detalle de implementación. No confíe en detalles de implementación no documentados. –

+4

Al usar la clase PropertyInfo y GetGet/SetMethod ya no es un problema de implementación. Es parte del marco en ese punto. – Kieron

+0

Kieron: suficiente. –

12

Hay tres maneras de hacer esto; el primero es usar GetGetMethod()/GetSetMethod() y crear un delegado con Delegate.CreateDelegate. El segundo es un lambda (¡no sirve de mucho para la reflexión!) [Es decir x => x.Foo]. El tercero es a través de Expression (.NET 3.5).

La lambda es la más fácil ;-P

class TestClass 
    { 
     public int Value { get; set; } 
    } 
    static void Main() 
    { 
     Func<TestClass, int> lambdaGet = x => x.Value; 
     Action<TestClass, int> lambdaSet = (x, val) => x.Value = val; 

     var prop = typeof(TestClass).GetProperty("Value"); 
     Func<TestClass, int> reflGet = (Func<TestClass, int>) Delegate.CreateDelegate(
      typeof(Func<TestClass, int>), prop.GetGetMethod()); 
     Action<TestClass, int> reflSet = (Action<TestClass, int>)Delegate.CreateDelegate(
      typeof(Action<TestClass, int>), prop.GetSetMethod()); 
    } 

para demostrar uso:

 TestClass foo = new TestClass(); 
     foo.Value = 1; 
     Console.WriteLine("Via property: " + foo.Value); 

     lambdaSet(foo, 2); 
     Console.WriteLine("Via lambda: " + lambdaGet(foo)); 

     reflSet(foo, 3); 
     Console.WriteLine("Via CreateDelegate: " + reflGet(foo)); 

Tenga en cuenta que si desea que el delegado que apunta a la instancia específica, se puede utilizar para el cierre de lambda , o la sobrecarga de CreateDelegate que acepta y instancia.

+1

¿Te importaría publicar ejemplos? –

+2

Por cierto, no he publicado un ejemplo de expresión, ya que tiende a ser detallado. Sin embargo, algunas publicaciones de Expression se encuentran en mi blog: http://marcgravell.blogspot.com/search/label/expression –

+0

¡Gracias por este ejemplo fácil de entender! –

Cuestiones relacionadas