C# 当多个方法重载匹配时,优先级是多少?
我正在努力理解C#中的OOP概念 在以下示例代码中:C# 当多个方法重载匹配时,优先级是多少?,c#,oop,C#,Oop,我正在努力理解C#中的OOP概念 在以下示例代码中: 为什么ins1更喜欢通用方法 为什么ins2,ins3更喜欢非通用方法 注意:当我注释掉任何一个“MyTestMethod”方法时,程序仍然会继续成功运行。此代码段不是生产中的内容。这只是我的训练样本。因此,请不要介意命名约定和标准 using System; namespace ConsoleApplication1 { class Program { public static void MyTestMe
ins1
更喜欢通用方法ins2
,ins3
更喜欢非通用方法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}");
}
}
}
使用系统;
命名空间控制台应用程序1
{
班级计划
{
公共静态void MyTestMethod(J输入)
{
Console.WriteLine($“Program.MyTestMethod:{input.Val}”);
}
公共静态void MyTestMethod(T输入),其中T:J
{
Console.WriteLine($“Program.MyTestMethod:{input.Val}”);
}
静态void Main(字符串[]参数)
{
J2 ins1=新的J2(1);
MyTestMethod(ins1);
J ins2=新的J(2);
MyTestMethod(ins2);
J ins3=新的J2(3);
MyTestMethod(ins3);
Console.ReadKey();
}
}
内部类别J
{
公共int Val{get;set;}
公共J(国际一)
{
Console.WriteLine($“混凝土基层{i}”);
Val=i;
}
}
内部类别J2:J
{
公共J2(内部i):基础(i*-1)
{
Console.WriteLine($“concrete{i}”);
}
}
}
为什么ins2,3更喜欢非泛型方法
因为在这两种情况下,变量的类型(不是实例化类型)都是J
,这与签名为MyTestMethod(J input)
的方法完全匹配。因此,重载解析规则告诉它采用该规则
为什么ins1更喜欢通用方法
由于T
可以在方法MyTestMethod(T输入)中J2
,其中T:J
,并且它可以强式键入T
为J2
,同样,它比其他方法的基类J
更匹配。因此,它将方法与类型参数相匹配。C规范的第7.5.3.2节是此处的相关部分-“更好的函数成员”
结果更简单地表现为:
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)
}
}
使用系统;
课堂测试
{
静态无效Foo(T项)
{
Console.WriteLine(“通用”);
}
静态void Foo(对象x)
{
Console.WriteLine(“非通用”);
}
静态void Main()
{
Foo(新对象());//调用Foo(对象)
Foo(“test”);//调用Foo(T)
}
}
在这两个调用中,两个重载都是适用的函数成员。在选择要调用的重载时,编译器首先检查从参数类型(或表达式)到参数类型的转换是否“更好”
当参数的类型为object
时,T
也被推断为object
,因此对于这两个候选者,转换是object
到object
的身份转换。在这一点上,7.5.3.2中的打破平局规则就涉及到了,第一个规则是:
如果MP是非泛型方法,而MQ是泛型方法,则MP优于MQ
这就是为什么在这种情况下选择非泛型重载
当参数类型为string
时,T
被推断为string
,因此我们必须比较从string
到string
的转换(对于泛型方法)到从string
到object
(对于非泛型方法)的转换。本规范第7.5.3.3节从以下内容开始:
给定从表达式E转换为类型T1的隐式转换C1,以及从表达式E转换为类型T2的隐式转换C2,如果至少满足以下条件之一,则C1比C2是更好的转换:
- E有一个类型S,存在从S到T1的标识转换,但不存在从S到T2的标识转换
在此上下文中,E是表达式“test”,S是类型
string
,T1是类型string
,T2是类型object
,因此从string到string的转换被认为更好,并且选择了泛型方法。您的代码根本没有任何泛型方法。@Jon现在有了。OP使用了
,它隐藏了可以解释为HTML标记的内容,例如
。请注意在以后开始时发布编译的代码,检查预览以确保它确实是您想要的代码。(一般来说,使用标记格式而不是HTML…@AntonGogolev:这个版本没有帮助,因为它是前泛型。我会直接进入真正的C#规范——不容易通过章节超链接,但可以让你下载wohle的东西。这是C#6.0@AntonGogolevYepp,速度很快(落后几秒钟,所以我自己没有回答)。补充答案。我认为,对于问题创建者来说,最好的读物是:它描述了“where(generic type constraint)”在c#中的工作方式。感谢@Thomas提供的有用评论。有相当多的关于方法优先级的资源确实对阅读很有用。泛型类型约束在这里并不真正相关——它在重载解析中不起作用。只有在重载解析选择了要使用的重载后,才会应用它来验证结果。(在本例中,这并不重要,因为两种方法都可以处理所有调用。)好的,同意。精确匹配总是赢。我的回答有错吗@JonSkeetNeh,我们不可能都是你…:)@JonSkeet希望更新是正确的。