尝试使用动态参数调用扩展方法时,为什么会出现CS1973错误 [英] Why is there an error CS1973 when trying to invoke extension method with dynamic argument

查看:116
本文介绍了尝试使用动态参数调用扩展方法时,为什么会出现CS1973错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

internal static class Program
{
    public static string ExtensionMethod(this string format, dynamic args)
    {
        return format + args.ToString();
    }

    private static void Main()
    {
        string test = "hello ";
        dynamic d = new { World = "world" };

        // Error CS1973  'string' has no applicable method named 'ExtensionMethod'
        //                but appears to have an extension method by that name. 
        //               Extension methods cannot be dynamically dispatched. 
        //               Consider casting the dynamic arguments or calling
        //               the extension method without the extension method syntax.
        var result = test.ExtensionMethod(d);

        // this syntax works fine
        var result2 = Program.ExtensionMethod(test, d);

        // for whatever reason, this works, too!
        var result3 = test.ExtensionMethod((object)d);

        // even this works...
        var result4 = test.ExtensionMethod(new { World = "world" });

        Console.WriteLine(result);
        Console.ReadLine();
    }
}

我不了解其背后的逻辑。我确实知道,扩展方法的 first 参数不能是动态的。而且我什至会理解,如果我传递了另一个动态信息,则调度是否将无法正常工作。但显然是的。它可以将其他类型映射为动态。但是当我通过方法要求的确切类型时,分派不起作用吗?不能将 dynamic 映射到 dynamic ?这对我来说没有意义。

I don't understand the logic behind this. I do understand, that the first argument of an extension method cannot be dynamic. And I even would understand if the dispatch would not work if I passed in something but another dynamic. But obviously it does. It can map other types to dynamic. But that the dispatch does not work when I pass the exact type required by the method? That it cannot map dynamic to dynamic? That does not make sense to me.

我可以阅读并理解该错误,并且我显然知道解决方法,但是任何人都可以启发我为什么吗?什么是我看不到的更深层次的问题?

I can read and understand the error and I obviously know the workarounds, but can anybody enlighten me why this error exists? What would be the deeper problem that I cannot see?

现有几个问题解释了为什么第一个论点( string )在这种情况下不能是动态的-如何调用动态类型的扩展方法?显示了将扩展调用转换为常规调用的解决方法。确实对我而言有效。

There are several existing questions explaining why first argument (string) in this case can't be dynamic - How to call an extension method of a dynamic type? showing workaround to convert extension call to regular call. Indeed it works in my case.

还有很多 CS1973是什么问题( https:/ /stackoverflow.com/search?q=CS1973 ),但其中大多数都再次处理第一个参数(此Xxxx dynamic (听起来很容易失败),或者只是表现出相同的行为而没有解释为什么像 System.Web.Mvc.HtmlHelper没有名为 Partial的适用方法(在强类型对象上调用已知扩展名,但传递了 dynamic 作为第二个参数)。

There are also plenty of "what is CS1973" questions (https://stackoverflow.com/search?q=CS1973) but again most of them deal with first (this Xxxx) argument being dynamic (which is sounds fair to fail) or just show same behavior without explanation why like 'System.Web.Mvc.HtmlHelper' has no applicable method named 'Partial' (calling known extension on strongly typed object but passing dynamic as second argument).

但这不能解释为什么在编译时仍然可以确定单个扩展方法的情况仍然无法使用这个问题是关于什么的。

But that does not explain why when single extension method can be determined at compile time still can't be used which is what this question is about.

推荐答案

因为扩展方法在编译时绑定。它们实际上是由编译器转换为静态方法调用的,这意味着

Because extension methods are bound at compile time. They are essentially converted by the compiler to a static method call, meaning

var result = test.ExtensionMethod(d);

由编译器转换为

var result = Program.ExtensionMethod(test, d);

任何参数为 dynamic ,然后将 all 绑定推迟到运行时。当前,运行时绑定程序不支持扩展方法的绑定,编译器知道,并生成错误。

When any of the parameters are dynamic, then all binding is deferred until run-time. The run-time binder does not currently support binding of extension methods, which the compiler knows, and generates an error.


我什至会理解,如果我传递了某种动态但又传递了另一种动态,则调度是否不起作用。

And I even would understand if the dispatch would not work if I passed in something but another dynamic.

请记住动态(例如 var )不是类型。它只是意味着我不知道编译时是什么类型-我将让动态运行时查看 actual 类型,然后确定如何处理它。

Remember that dynamic (like var) is not a type. It just means "I don't know what type this is at compile-time - I'll let the dynamic runtime look at the actual type and determine what do do with it then.

所以当您说:

dynamic d = new { World = "world" };

d 不是 a dynamic 。在运行时, d 的值将是匿名类型。

d is not "a dynamic". At runtime, the value of d will be an anonymous type.

可以使用动态绑定程序支持扩展方法吗?可能但是,到目前为止, * 的增加值还不值得(相对于其他事情)可以添加)以设计,实施,测试,发布和支持此类功能。如果您认为这对框架是有价值的补充,请随时在 http://connect.microsoft.com/

Could the dynamic binder support extension methods? Probably, but to date*, the added value has not been worth the cost (relative to other things that could be added) to design, implement, test, ship, and support such a feature. If you feel this would be a valuable addition to the framework, then feel free to submit a suggestion at http://connect.microsoft.com/.

我还要注意无需在您的计算机中使用 dynamic (尽管有人为)场景。如果使用 object 而不是 dynamic (并移动了),则会得到完全相同的行为(带有扩展方法支持)静态类的扩展方法):

I would also note that there is no need to use dynamic in your (albeit contrived) scenario. You'd get the exact same behavior (with extension method support) if you used object instead of dynamic (and moved the extension method to a static class):

public static string ExtensionMethod(this string format, object args)
{
    return format + args.ToString();
}
private static void Main()
{
    string test = "hello ";
    object d = new { World = "world" };

    // Error CS1973  'string' has no applicable method named 'ExtensionMethod'
    //                but appears to have an extension method by that name. 
    //               Extension methods cannot be dynamically dispatched. 
    //               Consider casting the dynamic arguments or calling
    //               the extension method without the extension method syntax.
    var result = test.ExtensionMethod(d);

    // this syntax works fine
    var result2 = Program.ExtensionMethod(test, d);

    // for whatever reason, this works, too!
    var result3 = test.ExtensionMethod((object)d);

    // even this works...
    var result4 = test.ExtensionMethod(new { World = "world" });

    Console.WriteLine(result);
    Console.ReadLine();
}






* 至少在2011年,在这种情况下找不到调用方法的问题被认为太难了-请参阅Eric Lippert的答案- https://stackoverflow.com/a/5313149/477420 ...这意味着为了正确解决动态扩展方法调用,DLR必须在运行时知道所有这些内容名称空间的嵌套和using指令已包含在您的源代码中。我们没有方便的机制将所有这些信息编码到调用站点中。

这篇关于尝试使用动态参数调用扩展方法时,为什么会出现CS1973错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆