多个方法重载匹配时的优先级是多少?

时间:2015-10-02 09:21:20

标签: c# oop

我正在尝试理解C#中的OOP概念。

在以下示例代码中:

  1. 为什么ins1更喜欢通用方法
  2. 为什么ins2ins3更喜欢非通用方法
  3. 注意:当我注释掉任何一个“MyTestMethod”方法时,程序仍然会继续成功运行。这段代码不是来自制作的东西。这只是我的训练样本。所以,请不要介意命名约定和标准。

    using System;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public static void MyTestMethod(J input)
            {
                Console.WriteLine($"Program.MyTestMethod: {input.Val}");
            }
            public static void MyTestMethod<T>(T input) where T : J
            {
                Console.WriteLine($"Program.MyTestMethod<T>: {input.Val}");
            }
    
            static void Main(string[] args)
            {
                J2 ins1 = new J2(1);
                MyTestMethod(ins1);
    
                J ins2 = new J(2);
                MyTestMethod(ins2);
    
                J ins3 = new J2(3);
                MyTestMethod(ins3);
    
                Console.ReadKey();
            }
        }
        internal class J
        {
            public int Val { get; set; }
            public J(int i)
            {
                Console.WriteLine($"concrete base {i}");
                Val = i;
            }
        }
        internal class J2 : J
        {
            public J2(int i) : base(i * -1)
            {
                Console.WriteLine($"concrete {i}");
            }
        }
    }
    

2 个答案:

答案 0 :(得分:5)

C#规范的第7.5.3.2节是这里的相关部分 - &#34;更好的功能成员&#34;。

结果更简单地表现为:

using System;

class Test
{
    static void Foo<T>(T item)
    {
        Console.WriteLine("Generic");
    }

    static void Foo(object x)
    {
        Console.WriteLine("Non-generic");
    }

    static void Main()
    {
        Foo(new object()); // Calls Foo(object)
        Foo("test"); // Calls Foo<T>(T)
    }
}

在两次调用中,两个重载都是适用的函数成员。在选择要调用的重载时,编译器首先检查从参数类型(或表达式)到参数类型的转换是&#34;更好&#34;。

当参数的类型为object时,T也被推断为object,因此对于两个候选者而言,转换是object的身份转换到object。那时,7.5.3.2的打破平局规则涉及到,第一个是:

  

如果M P 是非泛型方法且M Q 是通用方法,则M P 优于M Q

这就是为什么在这种情况下选择非泛型重载的原因。

当参数类型为string时,T被推断为string,因此我们必须比较从stringstring的转换(对于从stringobject的转换的通用方法(对于非泛型方法)。这里引入了C#规范的第7.5.3.3节,其中包括:

  

给定从表达式E转换为类型T1的隐式转换C1,以及从表达式E转换为类型T2的隐式转换C2,如果至少下列其中一个成立,则C1是比C2更好的转换:

     
      
  • E具有类型S,并且存在从S到T 1 的身份转换,但不存在从S到T 2
  • 的身份转换   

在此上下文中,E是表达式&#34; test&#34;,S是类型string,T 1 是类型string,T < sub> 2 是类型object,因此从字符串到字符串的转换被认为更好 - 并且选择了泛型方法。

答案 1 :(得分:3)

  

为什么ins2,3更喜欢非通用方法

因为在这两种情况下,变量类型(不是实例化类型)都是J,这与您的签名MyTestMethod(J input)方法完全匹配。因此,重载决策规则告诉它需要那个。

  

为什么ins1更喜欢通用方法

由于方法T中的J2可以是MyTestMethod(T input) where T : J,并且它可以强烈地将T类型设为J2,这是一个更好的匹配而不是基类J,来自您的其他方法。所以它将方法与类型参数匹配。