动态和其他类型的重载方法

Overloading Method with dynamic and other types

为什么我不能用 dynamicobject 参数重载方法。

void Method(dynamic arg) // Member with same signature is already declared
{
    Console.WriteLine("Dynamic");
}
void Method(object arg) // Member with same signature is already declared
{
    Console.WriteLine("Not Dynamic");
}

但我可以用 dynamic 和另一种类型 除了 对象或动态它自己来重载方法。

void Method(dynamic arg)
{
    Console.WriteLine("Dynamic");
}
void Method(string arg)
{
    Console.WriteLine("Not Dynamic");
}

正如您在第一个示例中看到的那样,编译器无法区分两个重载。

我认为第二个示例不应该太有效,因为字符串可以发送到两个重载。但是,编译器更喜欢使用已知类型调用重载。

我已经做了一些测试,看看它到底是如何工作的。

Method("");          // Prints: Not Dynamic
Method((dynamic)""); // Prints: Not Dynamic
Method(null);        // Prints: Not Dynamic
Method(???);         // Dynamic for any other type except string and null.

考虑第一个示例,编译器会这样决定:

Method(new object());// Prints: Not Dynamic
Method((object)5);   // Prints: Not Dynamic
Method(???);          // Prints: Dynamic for any other type except object and null.

那么编译器的困惑在哪里呢?为什么我不能有这样的重载?

来自 C# 5.0 规范,4.7 动态类型:

The type dynamic has special meaning in C#. Its purpose is to allow dynamic binding, which is described in detail in §7.2.2. dynamic is considered identical to object except in the following respects:
• Operations on expressions of type dynamic can be dynamically bound (§7.2.2).
• Type inference (§7.5.2) will prefer dynamic over object if both are candidates.
Because of this equivalence, the following holds:
• There is an implicit identity conversion between object and dynamic, and between constructed types that are the same when replacing dynamic with object
• Implicit and explicit conversions to and from object also apply to and from dynamic.
Method signatures that are the same when replacing dynamic with object are considered the same signature

事实上,一旦您的代码被编译,将 dynamic 作为参数的方法实际上与使用 object 声明相同的方法是一样的。只是在方法内部,可以动态使用 dynamic 参数(即使用 运行 时间绑定)。

因此,您的第一个示例方法对与您使用 object.

参数类型声明这两个方法基本相同

在你的第二个例子中,就像你可以有一个参数为 object 而另一个参数为 string 的重载一样,你也可以使用 [=10 配对一个方法=] 使用 string.

的同名方法

根据 C# 的重载解析规则(也在规范中),只要方法参数列表在允许选择一个方法重载作为 "best" 重载的方式上有所不同,就不会编译-会出现时间错误。在您的特定示例中,将 string 以外的任何内容传递给方法会自动排除使用 string 作为参数的方法。在您传递 string 的情况下,重载解析规则 select string 重载作为 "best" 重载,因此不会发生编译错误。