拥有以下代码
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 :(得分:5)
只要实际返回值是引用类型,它应该没问题 - 但是对于值类型返回值,这是有意义的。 (有关更详细的解释,请参阅Eric Lippert关于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>
的实例。然后,您可以从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 });
}