我正在尝试为:
创建一个委托(作为测试)Public Overridable ReadOnly Property PropertyName() As String
我的直觉尝试是宣布这样的代表:
Public Delegate Function Test() As String
并实例化如下:
Dim t As Test = AddressOf e.PropertyName
但这引发了错误:
方法'Public Overridable ReadOnly属性PropertyName()As 字符串'没有签名 与代表'代表兼容 Function Test()As String'。
因为我正在处理一个属性,我试过这个:
Public Delegate Property Test() As String
但这会引发编译错误。
所以问题是,如何为某个属性创建委托?
请看这个链接:
答案 0 :(得分:36)
使用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());
}
}
答案 1 :(得分:10)
我只是创建了一个性能相当不错的助手: 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)));
}
答案 2 :(得分:4)
以下是Marc Gravell's response的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 '是此示例的基础。
答案 3 :(得分:2)
这是个好主意
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
中 last 对象的属性值在这种情况下,您应该调用方法:
foreach (var e in Collection)
funcs.Add(new Func<int>(e.GetPropValue));
答案 4 :(得分:0)
这是一个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() - 代码中的某个地方,所有与你的事件相关的方法也会被一个接一个地调用。
答案 5 :(得分:0)
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())