【问题标题】:Issue with delegate return type委托返回类型的问题
【发布时间】:2011-03-10 17:57:30
【问题描述】:

有以下代码

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) 方法并创建一个委托以供以后调用。

【问题讨论】:

  • 你是不是严格卡在 .NET 2.0 平台上?
  • 您能否向我们展示它失败的Parse 方法的声明?
  • 也许你想写的和我的Parse<T> github.com/CodeInChaos/ChaosUtil/blob/master/Chaos.Util/… 类似,只是你可能需要用对象替换一些Ts。
  • @Mr.失望是的。
  • @Ani 采用任何整数类型或DateTime

标签: .net reflection delegates .net-2.0


【解决方案1】:

只要真正的返回值是引用类型就应该没问题 - 但是对于值类型返回值来说,失败是有意义的。 (有关更详细的解释,请参阅 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&lt;T&gt; 的实例。然后,您可以从 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 });
}

【讨论】:

  • 这很好,但我建议改用Converter&lt;string, T&gt;; OP 在 .NET 2 上。
  • 除非我在这里遗漏了什么,这归结为创建Func&lt;string, T&gt; parser 的实例,这正是我的问题所在。我不能把 T 当作泛型。
  • @liho1eye:是的,你可以——你只需要用泛型做那个部分。我保留了您的 nongeneric API(因为您将返回 ParseHandler),但您将通过方法中的反射使用泛型。
  • @Jon 我仍然很困惑......我如何从MethodInfo 的实例到BuildParseHandler&lt;MethodInfo.ReturnType&gt;
  • @liho1eye:现在已编辑,但我需要让孩子们准备睡觉,所以我需要一段时间才能再次回复。
猜你喜欢
  • 1970-01-01
  • 2021-02-22
  • 2010-10-29
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 2015-05-28
  • 1970-01-01
相关资源
最近更新 更多