尝试访问Int或DateTime属性时,Open Delegate失败

本文关键字:Open Delegate 失败 属性 DateTime 访问 Int | 更新日期: 2023-09-27 18:26:24

我一直在测试使用委托而不是反射进行一些对象排序,它对字符串属性很好,但如果我尝试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属性时,Open Delegate失败

为什么它适用于字符串或其他类,而不适用于Int或DateTime?

因为返回int的方法不是返回object引用的方法。必须有装箱转换-所以必须这样做,Delegate.CreateDelegate正试图提供一个委托,调用该委托并返回结果,而不涉及值转换。

这样做有点痛苦,但基本上我怀疑您应该构建一个具有适当返回值的Func,并直接使用它,您应该通过一个包装委托来调用"真实"委托并将结果框起来。

(请注意,在您的示例代码中,您每次都要创建委托,这不会比反射快。希望您的真实代码更明智:)

如果你看一下protobuf-csharp-port中的这段代码,你会发现我有一个方法可以做到这一点——lambda表达式调用强类型委托,然后使用到object的隐式转换(必要时装箱)来提供值。你应该能够使用非常相似的东西。但是,如果您正在排序,您真的想要Func<T, object>吗?如果使用强类型委托,则可以避免所有这些装箱。