[英]Generic extension methods in C#: what will happen in this edge case?
在我最近的一个问题中,我了解到如果有多个扩展方法具有与给定类型匹配的约束,则将选择最具体的扩展方法。 这让我思考 - 编译器如何确定哪一个“更具体”? 结果会是什么?
假设我有以下课程:
public MyClass : IComparable, IDisposable
{
// Implementation of members
}
public static class MyExtensions
{
public static void DoSomething<T>(this T item)
where T : IComparable
{ /* whatever */ }
public static void DoSomething<T>(this T item)
where T : IDisposable
{ /* whatever else */ }
}
如果我现在使用扩展方法
var instance = new MyClass();
instance.DoSomething();
将使用哪种方法? 或者编译器会抛出错误?
注意:我不是说这是好设计,甚至我说我需要这样做。 但是“更具体”这个词足以让我思考这一点,现在我必须知道! :P
更新:我想我是不是真的在上面的例子中会发生什么 ,在为什么感兴趣。 因为我做过类似的事情,所以我想到了
public static class CollectionExtensions
{
public static void DoSomething<T>(this T items) where T : IList { ... }
public static void DoSomething<T>(this T items) where T : IEnumerable { ... }
}
编译器知道为new List<Something>().DoSomething()
选择第一种方法,因为它与传递的类型“更接近”。 我当时感兴趣的是“在这种情况下更接近的意思是什么?如果约束来自两个不同的继承链,编译器将如何反应?为什么?”
它根本不会编译并抛出编译时错误,说两个方法之间的调用是不明确的。
类型'MyExtensions'已经定义了一个名为'DoSomething'的成员,它具有相同的参数类型。
这就是编译器给出这样的错误的原因。 扩展方法只是语法糖,它们所做的就是为任何类型带来流畅性和可读性。
检查此代码..
var instance = new MyClass();
instance.DoSomething();
编译器将此代码替换为以下内容。
var instance = new MyClass();
MyExtensions.DoSomething(instance);
//Compiler gets confused. Which one to call IComparable or IDisposable
在你的情况下编译器会混淆,因为方法调用有两个匹配的签名,它会给你所说的错误。
通用约束不被视为方法签名的一部分。 编译器将这两种方法视为具有相同签名的方法。 所以你会得到编译错误,说已经定义了DoSomething
方法。
public static void DoSomething<T>(this T item)
where T : IComparable
{ /* whatever */ }
public static void DoSomething<T>(this T item)
where T : IDisposable
{ /* whatever else */ }
请考虑以下示例:
class MyClass {}
static class MyClassExtensions
{
public static void DoSomething<T>(this T item, List<string> someList)
{
Console.WriteLine("Method with List in signature is called.");
}
public static void DoSomething<T>(this T item, IEnumerable<string> someEnumerable)
{
Console.WriteLine("Method with IEnumerable in signature is called.");
}
}
在此示例中,使用以下内容进行测试时:
var myClass = new MyClass();
myClass.DoSomething(new List<string>());
调用扩展类中的第一个方法。 简而言之,这意味着编译器确定更接近传递的参数的签名,并使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.