要从方法创建委托,您可以使用编译类型安全语法:
private int Method() { ... }
// and create the delegate to Method...
Func<int> d = Method;
属性是getter和setter方法的包装器,我想创建一个属性getter方法的委托。像
这样的东西public int Prop { get; set; }
Func<int> d = Prop;
// or...
Func<int> d = Prop_get;
不幸的是,这不起作用。我必须创建一个单独的lambda方法,当getter方法匹配委托签名时,这似乎是不必要的:
Func<int> d = () => Prop;
为了直接使用委托方法,我必须使用讨厌的反射,这不是编译类型安全的:
// something like this, not tested...
MethodInfo m = GetType().GetProperty("Prop").GetGetMethod();
Func<int> d = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), m);
有没有办法直接以编译安全的方式在属性获取方法上创建委托,类似于在顶部的普通方法上创建委托,而不需要使用中间lambda方法?
答案 0 :(得分:7)
据我所知,你已经写下了所有“有效”的变体。由于无法在普通代码中明确地寻址getter或setter(没有反射,所以),我认为没有办法做你想做的事。
答案 1 :(得分:1)
诀窍是Property
实际上只是隐藏的实际getter和/或setter方法的外观。编译器发出这些方法,并根据分别以 get _ 和 set _ 为前缀的Property
的名称命名它们。在下面的示例中,它将是int get_Value()
和void set_Value(int)
。因此,绕过所谓的&#34;属性&#34;并直接采取这些方法。
使用getter和/或setter方法,我们有两个选择。
我们可以创建一个绑定委托,其某些实例具有 this
值&#34;烧入。&#34;这类似于您对属性本身的期望,即此委托仅适用于访问该一个运行时实例。优点是,因为委托永久地绑定到它的实例,所以你不必传递额外的参数。
另一个选项是创建与特定目标实例无关的委托。虽然这些调用与以前完全相同的property-accessor方法,但在这种情况下,委托本身的Target
属性为空/ null。缺少任何 this
指针,未绑定的委托的方法签名会被更改,以显示着名的&#34; hidden this&#34 ;指针。
下面进一步讨论,但首先是代码。它说明了所有四种情况,getter / setter -vs-bound / unbound。
partial class Cls
{
static Cls()
{
UnboundGet = create<Func<Cls, int>>(null, mi_get);
UnboundSet = create<Action<Cls, int>>(null, mi_set);
}
public Cls()
{
BoundGet = create<Func<int>>(this, mi_get);
BoundSet = create<Action<int>>(this, mi_set);
}
public readonly static Func<Cls, int> UnboundGet;
public readonly static Action<Cls, int> UnboundSet;
public readonly Func<int> BoundGet;
public readonly Action<int> BoundSet;
public int Value { get; set; }
};
n.b。,这是指本帖子底部包含的一些帮助代码
总结一下,&#34;真正的签名&#34;实例方法与绑定委托的情况相同,但取消了。作为第一个参数,绑定代理通过提供它们在Target
属性中携带的实例来处理它。未绑定的委托是通用的,因此您不需要每个属性只需要一个getter / setter对。它们可用于在任何过去,现在或将来的运行时实例上访问该实例属性,但这意味着您必须显式传递所需的目标 this
对象作为第一个参数每次你调用getter / setter。
另请注意,即使此处的未绑定代理正在访问实例属性或方法,您实际上也不需要任何可行的Cls
运行时实例来创建代理。
这是一个演示。
static class demo
{
static demo()
{
var c1 = new Cls { Value = 111 };
var c2 = new Cls { Value = 222 };
Console.WriteLine("c1: {0} c2: {1}", c1, c2);
c1.BoundSet(c1.Value + 444);
Cls.UnboundSet(c2, c2.BoundGet() + 444);
Console.WriteLine("c1: {0} c2: {1}", c1, c2);
}
};
输出:
c1: 111 111 111 c2: 222 222 222 c1: 555 555 555 c2: 666 666 666
最后,我在这里放了一些帮助,以减少混乱。请注意,如果您计划构建大量绑定委托,则可以缓存并重用MethodInfo
。如果您更喜欢使用未绑定(静态)代理,则不需要保留它们;因为未绑定的委托对任何实例都是通用的,所以您可能决定永远不需要创建任何绑定的委托。
partial class Cls
{
static MethodInfo mi_get = typeof(Cls).GetMethod("get_Value"),
mi_set = typeof(Cls).GetMethod("set_Value");
static T create<T>(Object _this, MethodInfo mi) =>
(T)(Object)Delegate.CreateDelegate(typeof(T), _this, mi);
public override String ToString() =>
String.Format("{0} {1} {2}", Value, BoundGet(), Cls.UnboundGet(this));
}
答案 2 :(得分:0)
另一个选项(在.NET 3.0及更高版本中)将使用DependencyProperty
而不是传统属性。然后,您可以传递DependencyProperty
对象(而不是传递代理),并在需要时调用GetValue()
或SetValue()
。
(是的,我知道这是一个老问题,但当我尝试做一些非常相似的事情时,它是最重要的帖子之一。)
答案 3 :(得分:0)
已经花了几个小时对此进行了困惑,这是一种解决方案,适用于需要从另一个类中进行快速属性访问的情况。例如,如果您需要为以前未知的类编写缓存的属性映射,这些类不具备该CreateDelegate魔力的知识。
一个简单的无害数据类,例如:
public class DataClass
{
public int SomeProp { get; set; }
public DataClass(int value) => SomeProp = value;
}
通用访问器类,其中T1是包含属性的类的类型,而T2是该属性的类型,如下所示:
public class PropAccessor<T1, T2>
{
public readonly Func<T1, T2> Get;
public readonly Action<T1, T2> Set;
public PropAccessor(string propName)
{
Type t = typeof(T1);
MethodInfo getter = t.GetMethod("get_" + propName);
MethodInfo setter = t.GetMethod("set_" + propName);
Get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, getter);
Set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, setter);
}
}
然后您可以这样做:
var data = new DataClass(100);
var accessor = new PropAccessor<DataClass, int>("SomeProp");
log(accessor.Get(data));
accessor.Set(data, 200);
log(accessor.Get(data));
基本上,您可以在启动时通过反射遍历类,并为每个属性创建PropAccessors缓存,从而为您提供相当快的访问权限。
编辑:几个小时后。
最终得到这样的结果。 PropAccessor的抽象祖先是必需的,因此我实际上可以在Prop类中声明该类型的字段,而无需诉诸使用dynamic。最终比MethodInfo快10倍。调用getter和setter方法。
internal abstract class Accessor
{
public abstract void MakeAccessors(PropertyInfo pi);
public abstract object Get(object obj);
public abstract void Set(object obj, object value);
}
internal class PropAccessor<T1, T2> : Accessor
{
private Func<T1, T2> _get;
private Action<T1, T2> _set;
public override object Get(object obj) => _get((T1)obj);
public override void Set(object obj, object value) => _set((T1)obj, (T2)value);
public PropAccessor() { }
public override void MakeAccessors(PropertyInfo pi)
{
_get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, pi.GetMethod);
_set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, pi.SetMethod);
}
}
internal class Prop
{
public string name;
public int length;
public int offset;
public PropType type;
public Accessor accessor;
}
internal class PropMap
{
public UInt16 length;
public List<Prop> props;
internal PropMap()
{
length = 0;
props = new List<Prop>();
}
internal Prop Add(PropType propType, UInt16 size, PropertyInfo propInfo)
{
Prop p = new Prop()
{
name = propInfo.Name,
length = size,
offset = this.length,
type = propType,
Encode = encoder,
Decode = decoder,
};
Type accessorType = typeof(PropAccessor<,>).MakeGenericType(propInfo.DeclaringType, propInfo.PropertyType);
p.accessor = (Accessor)Activator.CreateInstance(accessorType);
p.accessor.MakeAccessors(propInfo);
this.length += size;
props.Add(p);
return p;
}
}