C#中的重载分辨率,扩展方法和通用性

我在C#源代码中有以下场景:

class A{} class Dispatch{} static class DispatchExt { public static void D(this Dispatch d, int a) { Console.WriteLine("Generic D chosen with a = " + a.ToString()); } public static void D(this Dispatch d, int a) { Console.WriteLine("D chosen with a = " + a.ToString()); } } class Program { static void D(Dispatch d, int a) { dD(a); } static void Main(string[] args) { int a = 5; var dispatch = new Dispatch(); dispatch.D(a); D(dispatch, a); } } 

当我运行此代码时输出为:

D选择a = 5”

“通用D选择a = 5”

这个结果让我感到惊讶,因为在这两种情况下,我都期待“ D选择a = 5”。

我想知道这种情况下的一般重载解析规则是什么,或导致此输出的任何内容。 此外,我想知道是否有办法在两种情况下实现第一次输出。

扩展方法是语法糖,在编译时使用仅从静态类型系统获取的信息进行解释。

举个例子,你有这个:

 dispatch.D(a); 

dispatch的类型为Dispatch ,其中存在扩展方法。 因此,编译器将其转换为DispatchExt.D(dispatch, a) (非generics版本)。

在你的第二个例子中,你有这个:

 dD(a); 

d的类型为Dispatch 。 所以这采用了generics扩展方法DispatchExt.D(d, a)

由于转换发生在编译时,因此不考虑实际的运行时类型。


这是顺便说一句。 在其他情况下确定重载时使用的相同行为:仅考虑静态编译时类型:

 A a = new A(); B b = new B(); A ba = b; Test(a); // "a" Test(b); // "b" Test(ba); // "a" 

使用以下定义:

 public void Test(A a) { Console.WriteLine("a"); } public void Test(B a) { Console.WriteLine("b"); } public class A {} public class B : A {} 

我认为你的意思是这样的 – 一种自称的链式方法。 我做了一个数字总和的多次调用。

 using System; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { var magic = new Magic(); var sum = magic.MagicAdd(2).MagicAdd(20).MagicAdd(50).MagicAdd(20).Result; Console.WriteLine(sum); Console.ReadKey(); } } public class Magic { public int Result { get; set; } //method chaining public Magic MagicAdd(int num) { this.Sum(num); return this; } public int Sum(int x) { this.Result = this.Result + x; return this.Result; } } }