2011-03-10 150 views
2

有无以下代码问题与委托返回类型

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; 
} 

是在Delegate.CreateDelegate()呼叫与吹“错误结合靶的方法”。显然是因为ParseHandler被定义为返回object而不是类型特定的返回值。

我不知道类型在编译类型,所以我不能取代type参数与通用(如果我做了,那么整个功能将不需要)。

对如何处理这个有点困惑。所需的行为是为给定类型找到public static Parse(string)方法,并创建一个委托让它稍后调用。

+0

您是否严格禁用.NET 2.0平台? – 2011-03-10 18:01:26

+1

你能向我们展示它失败的'Parse'方法的声明吗? – Ani 2011-03-10 18:03:44

+0

也许你想写的东西就像我的'解析'https://github.com/CodeInChaos/ChaosUtil/blob/master/Chaos.Util/Conversion.cs,除非你可能需要替换一些'T'对象。 – CodesInChaos 2011-03-10 18:09:01

回答

5

只要真实的返回值是一个引用类型,它就应该没问题 - 但这对于值类型返回值失败是有意义的。 (见埃里克利珀的约representation and identity职位更详细的解释。)

一种选择是创建一个通用类是这样的:

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); 
    } 
} 

在你GetParser方法,你会检查是否parse返回类型是一个值类型,如果是这样的话,通过反射创建一个BoxingParserDelegate<T>的实例。然后,您可以从BoxingParserDelegate的Parse方法创建ParseHandler实例。

这一切都会坦率地说有些尴尬,但应该工作。说实话,感觉应该有一个更简单的方法。

(在.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); } 
} 

这是有效要求编译器为您完成上述工作的一半。那么你只需要确定是否需要调用它,并在必要时用反射来完成。类似这样的:

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 }); 
} 
+0

这很好,但我建议使用'Converter '来代替;该OP是在.NET 2上。 – Ani 2011-03-10 18:21:41

+0

@Ani:谢谢,将会编辑。 – 2011-03-10 18:22:44

+0

除非我在这里丢失了一些东西,这归结于创建'Func 解析器'的实例,这正是我的问题摆在首位。我不能把T当作通用的。 – 2011-03-10 18:25:21