[英]How do I create a delegate for a .NET property?
我正在嘗試創建一個委托(作為測試):
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
但這會引發編譯錯誤。
所以問題是,我如何為一個財產代表?
看到這個鏈接:
使用AddressOf解決問題 - 如果你在編譯時知道prop-name,你可以(至少在C#中)使用anon-method / lambda:
Test t = delegate { return e.PropertyName; }; // C# 2.0
Test t = () => e.PropertyName; // C# 3.0
我不是VB專家,但反射器聲稱這與以下相同:
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<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());
}
}
我只是創建了一個具有相當好性能的幫助器: 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<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; }
}
}
像這樣使用它:
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>(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);
}
}
同樣,' Delegate.CreateDelegate '是這個例子的基礎。
這是個好主意
Test t = () => e.PropertyName; // C# 3.0
但要注意你是否正在做這樣的事情:
List<Func<int>> funcs = new List<Func<int>>();
foreach (var e in Collection)
funcs.Add(new Func<int>(() => e.Property));
打電話給:
foreach(var f in funcs)
f();
將始終返回Collection中最后一個對象的屬性值
在這種情況下,您應該調用方法:
foreach (var e in Collection)
funcs.Add(new Func<int>(e.GetPropValue));
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())
這是一個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() - 在你的代碼中的某個地方,並且一個接一個地調用與你的事件相關的所有方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.