C# 中的重载解析、扩展方法和泛型

Overload resolution, extension methods and genericity in C#

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

class A{}

class Dispatch<T>{}

static class DispatchExt
{
    public static void D<T>(this Dispatch<T> d, int a)
    {
         Console.WriteLine("Generic D chosen with a = " + a.ToString());
    }

    public static void D(this Dispatch<A> d, int a)
    {
         Console.WriteLine("D<A> chosen with a = " + a.ToString());
    }
}

class Program
{
     static void D<T>(Dispatch<T> d, int a)
     {
          d.D(a);
     }

     static void Main(string[] args)
     {
         int a = 5;
         var dispatch = new Dispatch<A>();
         dispatch.D(a);
         D(dispatch, a);
     }
}

当我运行这段代码的输出是:

"D<A> 选择了 = 5"

"Generic D chosen with a = 5"

这个结果让我很吃惊,因为在这两种情况下我都期望“D<A> chosen with a = 5”。

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

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

以你的第一个例子为例,你有这个:

dispatch.D(a);

dispatch 属于 Dispatch<A> 类型,存在扩展方法。所以编译器将其翻译成 DispatchExt.D(dispatch, a)(非泛型版本)。

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

d.D(a);

dDispatch<T> 类型。所以这采用通用扩展方法 DispatchExt.D<T>(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;

        }
    }
}