如何为.NET属性创建委托?

我正在尝试创建一个委托(作为测试):

Public Overridable ReadOnly Property PropertyName() As String 

我的直觉尝试是声明代表这样:

 Public Delegate Function Test() As String 

并实例化如下:

 Dim t As Test = AddressOf e.PropertyName 

但这会引发错误:

方法’Public Overridable ReadOnly Property PropertyName()As String’没有与委托’Delegate Function Test()As String’兼容的签名。

因为我正在处理一个属性,我试过这个:

 Public Delegate Property Test() As String 

但这会引发编译器错误。

所以问题是,我如何为一个财产代表?


看到这个链接:

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

使用AddressOf解决问题 – 如果你在编译时知道prop-name,你可以(至少在C#中)使用anon-method / lambda:

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

我不是VB专家,但reflection器声称这与以下相同:

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

那样有用吗?


原始答案:

您可以使用Delegate.CreateDelegate为属性创建委托; 这可以对任何类型的实例打开,对于单个实例是固定的 – 并且可以用于getter或setter; 我将在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 getForAnyFoo = (Func) Delegate.CreateDelegate(typeof(Func), null, prop.GetGetMethod()); Func getForFixedFoo = (Func) Delegate.CreateDelegate(typeof(Func), foo, prop.GetGetMethod()); Action setForAnyFoo = (Action) Delegate.CreateDelegate(typeof(Action), null, prop.GetSetMethod()); Action setForFixedFoo = (Action) Delegate.CreateDelegate(typeof(Action), foo, prop.GetSetMethod()); setForAnyFoo(foo, "abc"); Console.WriteLine(getForAnyFoo(foo)); setForFixedFoo("def"); Console.WriteLine(getForFixedFoo()); } } 

我只是创建了一个具有相当好性能的帮助程序: http : //thibaud60.blogspot.com/2010/10/fast-property-accessor-without-dynamic.html它不使用IL / Emit方法,而且速度非常快!

由oscilatingcretin编辑2015/10/23

源包含一些套管问题,并且必须删除特殊的="" 。 在链接腐烂之前,我想我会发布一个清理版本的源码,以便于复制意大利面,以及如何使用它的示例。

修改来源

 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 _cache = new ConcurrentDictionary(); 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 : IPropertyAccessor where TObject : class { private Func Getter; private Action Setter; public PropertyWrapper(PropertyInfo PropertyInfo) { this.PropertyInfo = PropertyInfo; MethodInfo GetterInfo = PropertyInfo.GetGetMethod(true); MethodInfo SetterInfo = PropertyInfo.GetSetMethod(true); Getter = (Func)Delegate.CreateDelegate (typeof(Func), GetterInfo); Setter = (Action)Delegate.CreateDelegate (typeof(Action), 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; } } } 

像这样用它:

 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))); } 

这是Marc Gravell的 C#/。NET 2.0版本的回复 :

 using System; using System.Reflection; class Program { private delegate void SetValue(T value); private delegate T GetValue(); 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 setValue = (SetValue) Delegate.CreateDelegate(typeof (SetValue), foo, methodInfo); setValue("abc"); // getter methodInfo = property.GetGetMethod(); GetValue getValue = (GetValue) Delegate.CreateDelegate(typeof (GetValue), foo, methodInfo); string myValue = getValue(); // output results Console.WriteLine(myValue); } } 

同样,’ Delegate.CreateDelegate ‘是这个例子的基础。

这是个好主意

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

但要注意你是否正在做这样的事情:

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

打电话给:

 foreach(var f in funcs) f(); 

将始终返回Collection中最后一个对象的属性值

在这种情况下,您应该调用方法:

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

这是一个C#示例,但所有类型都是相同的:

首先创建接口(委托)。 请记住,附加到委托的方法必须返回相同的类型,并采用与委托声明相同的参数。 不要在与事件相同的范围内定义委托。

 public delegate void delgJournalBaseModified(); 

根据代表制作活动:

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

定义一个方法,该方法可以绑定到具有与委托相同的接口的事件。

 void UpdateEntryList() { } 

将方法绑定到事件。 触发事件时调用该方法。 您可以将多种方法绑定到事件中。 我不知道极限。 这可能是疯狂的事情。

  JournalBase.evntJournalModified += new delgJournalBaseModified(UpdateEntryList); 

这里发生的是该方法被添加为您的事件的回调。 触发事件时,将调用您的方法。

接下来,我们创建一个方法,在调用时触发事件:

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

然后你只需调用方法 – JournalBase_Modified() – 在你的代码中的某个地方,所有与你的事件相关的方法也会被一个接一个地调用。

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())