委托返回类型的问题

Ili*_*a G 2 .net reflection delegates .net-2.0

有以下代码

public delegate object ParseHandler(string s);
public static ParseHandler GetParser(Type t)
{
    MethodInfo parse = t.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
        null, new Type[] { typeof(string) }, null);

    if (parse != null)
        return (ParseHandler)Delegate.CreateDelegate(typeof(ParseHandler), parse, true);

    return null;
}
Run Code Online (Sandbox Code Playgroud)

正在Delegate.CreateDelegate()通过"绑定到目标方法的错误" 进行调用.显然是因为ParseHandler被定义为返回object而不是类型特定的返回值.

我不知道在编译类型的类型,所以我不能type用泛型替换参数(如果我这样做,那么将不需要整个函数).

对如何处理这个问题有点困惑.所需的行为是查找public static Parse(string)给定类型的方法并为其稍后调用创建委托.

Jon*_*eet 5

只要实际返回值是引用类型,它应该没问题 - 但是对于值类型返回值来说,这是有意义的.(有关更多详细说明,请参阅Eric Lippert关于表示和身份的帖子.)

一种选择是创建一个这样的泛型类:

public class BoxingParserDelegate<T>
{
    private readonly Converter<string, T> parser;

    public BoxingParserDelegate(Converter<string, T> parser)
    {
        this.parser = parser;
    }

    public object Parse(string x)
    {
        return parser(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

在GetParser方法中,您将检查返回类型parse是否为值类型,如果是,则创建BoxingParserDelegate<T>via反射的实例.然后,您可以ParseHandler从Parse方法创建实例BoxingParserDelegate.

这一切都有点尴尬,但应该有效.说实话,感觉应该有一个更简单的方法.

(在.NET 3.5或更高版本上,我建议使用表达式树,但我只是看到了.NET 2.0标记.)

编辑:啊哈,想到了稍微简单的方法:

public static ParseHandler BuildParseHandler<T>(Converter<string, T> converter)
{
    // Performs boxing automatically
    return delegate(string x) { return converter(x); }
}
Run Code Online (Sandbox Code Playgroud)

有效地要求编译器做一半以上的工作适合你.然后你只需要确定是否需要调用它,并在必要时使用反射来完成.像这样的东西:

public static ParseHandler GetParser(Type t)
{
    MethodInfo parse = t.GetMethod("Parse",
        BindingFlags.Static | BindingFlags.Public,
        null, new Type[] { typeof(string) }, null);

    // Method not found
    if (parse == null)
    {
        return null;
    }

    // Reference type - use delegate covariance
    if (!parse.ReturnType.IsValueType)
    {
        return (ParseHandler) Delegate.CreateDelegate(typeof(ParseHandler),
            parse, true);
    }

    // Tricky situation: call BuildParseHandler with generics
    Type delegateType = typeof(Converter<,>).MakeGenericType(typeof(string),
                                                             parse.ReturnType);
    object converter = Delegate.CreateDelegate(delegateType, parse, true);

    // You may need extra work to get this... let me know whether or not it works.
    // Obviously if you make it private, you'll need extra binding flags.
    MethodInfo method = typeof(TypeContainingThisMethod)
                            .GetMethod("BuildParseHandler");
    method = method.MakeGenericMethod(parse.ReturnType);

    return (ParseHandler) method.Invoke(null, new object[] { converter });
}
Run Code Online (Sandbox Code Playgroud)