with new net method delegate c# vb.net delegates

c# - new - ¿Cómo creo un delegado para una propiedad.NET?



vb net addressof with parameters (6)

Acabo de crear un ayudante con un rendimiento bastante bueno: http://thibaud60.blogspot.com/2010/10/fast-property-accessor-without-dynamic.html ¡No utiliza el enfoque IL / Emit y es muy rápido!

Edición por oscilatingcretin 2015/10/23

La fuente contiene algunos problemas de carcasa y peculiar ="" que deben eliminarse. Antes de que se establezca la vinculación de enlaces, pensé en publicar una versión limpia de la fuente para copiar fácilmente la pasta, así como un ejemplo de cómo usarla.

Fuente revisada

using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace Tools.Reflection { public interface IPropertyAccessor { PropertyInfo PropertyInfo { get; } object GetValue(object source); void SetValue(object source, object value); } public static class PropertyInfoHelper { private static ConcurrentDictionary<PropertyInfo, IPropertyAccessor> _cache = new ConcurrentDictionary<PropertyInfo, IPropertyAccessor>(); public static IPropertyAccessor GetAccessor(PropertyInfo propertyInfo) { IPropertyAccessor result = null; if (!_cache.TryGetValue(propertyInfo, out result)) { result = CreateAccessor(propertyInfo); _cache.TryAdd(propertyInfo, result); ; } return result; } public static IPropertyAccessor CreateAccessor(PropertyInfo PropertyInfo) { var GenType = typeof(PropertyWrapper<,>) .MakeGenericType(PropertyInfo.DeclaringType, PropertyInfo.PropertyType); return (IPropertyAccessor)Activator.CreateInstance(GenType, PropertyInfo); } } internal class PropertyWrapper<TObject, TValue> : IPropertyAccessor where TObject : class { private Func<TObject, TValue> Getter; private Action<TObject, TValue> Setter; public PropertyWrapper(PropertyInfo PropertyInfo) { this.PropertyInfo = PropertyInfo; MethodInfo GetterInfo = PropertyInfo.GetGetMethod(true); MethodInfo SetterInfo = PropertyInfo.GetSetMethod(true); Getter = (Func<TObject, TValue>)Delegate.CreateDelegate (typeof(Func<TObject, TValue>), GetterInfo); Setter = (Action<TObject, TValue>)Delegate.CreateDelegate (typeof(Action<TObject, TValue>), SetterInfo); } object IPropertyAccessor.GetValue(object source) { return Getter(source as TObject); } void IPropertyAccessor.SetValue(object source, object value) { Setter(source as TObject, (TValue)value); } public PropertyInfo PropertyInfo { get; private set; } } }

Úsalo así:

public class MyClass { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } MyClass e = new MyClass(); IPropertyAccessor[] Accessors = e.GetType().GetProperties() .Select(pi => PropertyInfoHelper.CreateAccessor(pi)).ToArray(); foreach (var Accessor in Accessors) { Type pt = Accessor.PropertyInfo.PropertyType; if (pt == typeof(string)) Accessor.SetValue(e, Guid.NewGuid().ToString("n").Substring(0, 9)); else if (pt == typeof(int)) Accessor.SetValue(e, new Random().Next(0, int.MaxValue)); Console.WriteLine(string.Format("{0}:{1}", Accessor.PropertyInfo.Name, Accessor.GetValue(e))); }

Estoy tratando de crear un delegado (como prueba) para:

Public Overridable ReadOnly Property PropertyName() As String

Mi intento intuitivo fue declarar al delegado así:

Public Delegate Function Test() As String

Y la instanciación de esta manera:

Dim t As Test = AddressOf e.PropertyName

Pero esto arroja el error:

El método ''Public Overridable ReadOnly Property PropertyName () As String'' no tiene una firma compatible con el delegado ''Delegate Function Test () As String''.

Entonces, como estaba tratando con una propiedad, intenté esto:

Public Delegate Property Test() As String

Pero esto arroja un error de compilación.

Entonces la pregunta es, ¿cómo puedo hacer un delegado para una propiedad?

Vea este enlace:

http://peisker.net/dotnet/propertydelegates.htm


Aquí hay un ejemplo de C # pero todos los tipos son iguales:

Primero crea la interfaz (delegado). Recuerde, un método que adjunte a su delegado debe devolver el mismo tipo y tomar los mismos parámetros que la declaración de su delegado. No defina a su delegado en el mismo ámbito que su evento.

public delegate void delgJournalBaseModified();

Haz un evento basado en el delegado:

public static class JournalBase { public static event delgJournalBaseModified evntJournalModified; };

Defina un método que pueda vincularse a su evento que tenga una interfaz idéntica al delegado.

void UpdateEntryList() { }

Atar el método al evento. El método se llama cuando se activa el evento. Puedes atar tantos métodos a tu evento. No sé el límite. Probablemente sea algo loco.

JournalBase.evntJournalModified += new delgJournalBaseModified(UpdateEntryList);

Lo que sucede aquí es que el método se agrega como devolución de llamada para su evento. Cuando se dispare el evento, se llamará a su (s) método (s).

A continuación hacemos un método que activará el evento cuando se llame:

public static class JournalBase { public static void JournalBase_Modified() { if (evntJournalModified != null) evntJournalModified(); } };

Luego simplemente llama al método - JournalBase_Modified () - en algún lugar de su código y también se llaman todos los métodos relacionados con su evento, uno tras otro.


Aquí hay una versión de C # / .NET 2.0 de la respuesta de Marc Gravell :

using System; using System.Reflection; class Program { private delegate void SetValue<T>(T value); private delegate T GetValue<T>(); private class Foo { private string _bar; public string Bar { get { return _bar; } set { _bar = value; } } } static void Main() { Foo foo = new Foo(); Type type = typeof (Foo); PropertyInfo property = type.GetProperty("Bar"); // setter MethodInfo methodInfo = property.GetSetMethod(); SetValue<string> setValue = (SetValue<string>) Delegate.CreateDelegate(typeof (SetValue<string>), foo, methodInfo); setValue("abc"); // getter methodInfo = property.GetGetMethod(); GetValue<string> getValue = (GetValue<string>) Delegate.CreateDelegate(typeof (GetValue<string>), foo, methodInfo); string myValue = getValue(); // output results Console.WriteLine(myValue); } }

Nuevamente, '' Delegate.CreateDelegate '' es lo fundamental para este ejemplo.


Eso es una buena idea

Test t = () => e.PropertyName; // C# 3.0

Pero ten cuidado si estás haciendo algo como esto:

List<Func<int>> funcs = new List<Func<int>>(); foreach (var e in Collection) funcs.Add(new Func<int>(() => e.Property));

Llamando a esto:

foreach(var f in funcs) f();

Siempre devolverá el valor de la propiedad del último objeto en Colección.

En este caso deberías llamar método:

foreach (var e in Collection) funcs.Add(new Func<int>(e.GetPropValue));


Re el problema al usar AddressOf: si conoce el nombre de prop en el momento de la compilación, puede (al menos en C #) usar un anon-method / lambda:

Test t = delegate { return e.PropertyName; }; // C# 2.0 Test t = () => e.PropertyName; // C# 3.0

No soy un experto en VB, pero el reflector afirma que esto es lo mismo que:

Dim t As Test = Function Return e.PropertyName End Function

¿Eso funciona?

Respuesta original:

Se crean delegados para las propiedades con Delegate.CreateDelegate ; esto puede estar abierto para cualquier instancia del tipo, de fijo para una sola instancia, y puede ser para getter o setter; Daré un ejemplo en C # ...

using System; using System.Reflection; class Foo { public string Bar { get; set; } } class Program { static void Main() { PropertyInfo prop = typeof(Foo).GetProperty("Bar"); Foo foo = new Foo(); // create an open "getter" delegate Func<Foo, string> getForAnyFoo = (Func<Foo, string>) Delegate.CreateDelegate(typeof(Func<Foo, string>), null, prop.GetGetMethod()); Func<string> getForFixedFoo = (Func<string>) Delegate.CreateDelegate(typeof(Func<string>), foo, prop.GetGetMethod()); Action<Foo,string> setForAnyFoo = (Action<Foo,string>) Delegate.CreateDelegate(typeof(Action<Foo, string>), null, prop.GetSetMethod()); Action<string> setForFixedFoo = (Action<string>) Delegate.CreateDelegate(typeof(Action<string>), foo, prop.GetSetMethod()); setForAnyFoo(foo, "abc"); Console.WriteLine(getForAnyFoo(foo)); setForFixedFoo("def"); Console.WriteLine(getForFixedFoo()); } }


Versión VB:

Dim prop As PropertyInfo = GetType(foo).GetProperty("bar") Dim foo1 As New foo Dim getForAnyFoo As Func(Of foo, String) = TryCast([Delegate].CreateDelegate(GetType(Func(Of foo, String)), Nothing, prop.GetGetMethod()), Func(Of foo, String)) Dim setForAnyFoo As Action(Of foo, String) = TryCast([Delegate].CreateDelegate(GetType(Action(Of foo, String)), Nothing, prop.GetSetMethod()), Action(Of foo, String)) Dim getForFixedFoo As Func(Of String) = TryCast([Delegate].CreateDelegate(GetType(Func(Of String)), foo1, prop.GetGetMethod()), Func(Of String)) Dim setForFixedFoo As Action(Of String) = TryCast([Delegate].CreateDelegate(GetType(Action(Of String)), foo1, prop.GetSetMethod()), Action(Of String)) setForAnyFoo(foo1, "abc") Debug.WriteLine(getForAnyFoo(foo1)) setForFixedFoo("def") Debug.WriteLine(getForFixedFoo())