我一直在测试使用委托而不是反射进行一些对象排序,它对字符串属性很好,但如果我尝试Int(或DateTime),它会失败并抛出
绑定到目标方法时出错。
class Program
{
static void Main(string[] args)
{
var sample = new SampleClass() { Num = 13, Text = "Sample" };
Console.WriteLine(ReadProp(sample,"Text")); //Works
Console.WriteLine(ReadProp(sample, "classProp")); //Works
Console.WriteLine(ReadProp(sample, "Num")); //Throws 'Error binding to target method.'
}
//Use a Delegate to improve speed of accessing property instead of reflection
static object ReadProp(SampleClass obj, string propName)
{
var method = obj.GetType().GetProperty(propName).GetGetMethod();
var getForProp = (Func<SampleClass, object>)Delegate.CreateDelegate(typeof(Func<SampleClass, object>), null, method);
return getForProp(obj);
}
}
//A sample class for illustration purposes
class SampleClass
{
public string Text { get; set; }
public int Num { get; set; }
public SampleClass classProp { get; set; }
}
我的问题是:为什么它适用于字符串或其他类,而不适用于Int或DateTime
我可以看到,如果我将Func<SampleClass, object>
更改为Func<SampleClass, int>
,它将适用于我的Int,但我希望对象同时适用于两者。
为什么它适用于字符串或其他类,而不适用于Int或DateTime?
因为返回int
的方法不是返回object
引用的方法。必须有装箱转换-所以必须这样做,Delegate.CreateDelegate
正试图提供一个委托,仅调用该委托并返回结果,而不涉及值转换。
这样做有点痛苦,但基本上我怀疑您应该构建一个具有适当返回值的Func
,并直接使用它或,您应该通过一个包装委托来调用"真实"委托并将结果框起来。
(请注意,在您的示例代码中,您每次都要创建委托,这不会比反射快。希望您的真实代码更明智:)
如果你看一下protobuf-csharp-port
中的这段代码,你会发现我有一个方法可以做到这一点——lambda表达式调用强类型委托,然后使用到object
的隐式转换(必要时装箱)来提供值。你应该能够使用非常相似的东西。但是,如果您正在排序,您真的想要Func<T, object>
吗?如果使用强类型委托,则可以避免所有这些装箱。