// Some interface method signature
public interface IList : ICollection {
...
bool Contains(Object value);
...
}
public interface IList<T> : ICollection<T> { ... }
public interface ICollection<T> : IEnumerable<T> {
...
bool Contains(T item);
...
}
下面是List
的源代码:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T> {
...
public bool Contains(T item) {
...
}
bool System.Collections.IList.Contains(Object item) {
...
}
}
您可以看到List
使用显式接口(interface)方法实现(显式指定接口(interface)名称)来实现非泛型Contains
。但我对显式接口(interface)方法实现的了解是,只有当两个接口(interface)方法具有相同签名时才需要这样做。
但是对于 public bool Contains(T item)
和 public bool Contains(Object item)
来说,它们是不同的方法,因为它们具有不同的签名(通用参数和非参数)通用参数),因此 List
将被实现为:
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T> {
public bool Contains(T item) { ... }
public bool Contains(Object item) { ... }
}
那么List为什么要使用显式接口(interface)方法实现来实现非泛型接口(interface)方法呢?我看不出在这种情况下使用显式接口(interface)方法实现有任何好处。我在这里遗漏了什么吗?
最佳答案
You can see that
List
uses explicit interface method implementation (explicitly specify the interface's name) to implement the non-genericContains
确实。
但那是因为 IList
接口(interface)(不是 IList<T>
)已经有几十年的历史了 - 从原始的、黑暗的时代开始,在 .NET 支持泛型之前(.NET 1.0 于 2001 年问世 - 直到 .NET 才添加泛型) 2005 年框架 2.0)。那真是一个被上帝遗弃的时代。
List<T>
(但不是 IList<T>
)实现 IList
接口(interface),以便新的通用 List<T>
可以被接受 IList
的旧代码使用(以允许保留对象身份且无需分配单独的 IList
实例)。
假设现在是 2005 年,您正在编写一些精彩的 C# 2.0 代码,这些代码使用奇特的新具体化泛型和 List<T>
- 但您需要与最后一次更新于 2004 年的库进行交互:
public void YourNewSexyGenericCode()
{
List<String> listOfString = new List<String>() { "a", "b", "c" };
OldAndBustedNET10CodeFrom2004( listOfString ); // <-- This works because List<String> implements IList.
foreach( String s in listOfString ) Console.WriteLine( s );
}
public void OldAndBustedNET10CodeFrom2004( IList listOfString )
{
listOfString.Add( "foo" );
listOfString.Add( "bar" );
listOfString.Add( "baz" );
return;
}
如果 List<T>
没有实现 IList
那么你就不得不做这样可怕的事情:
List<String> listOfString = new List<String>() { "a", "b", "c" };
// Step 1: Create a new separate IList and copy everything from your generic list into it.
IList classicList = new ArrayList();
classicList.AddRange( listOfString );
// Step 2: Pass the IList in:
OldAndBustedNET10CodeFrom2004( classicList );
// Step 3: Copy the elements back, in a type-safe manner:
foreach( Object maybeString in classicList )
{
String asString = maybeString as String; // The `is String str` syntax wasn't available back in C# 2.0
if( asString != null )
{
listOfString.Add( asString );
}
}
// Step 4: Continue:
foreach( String s in listOfString ) Console.WriteLine( s );
But what I know about explicit interface method implementation is, you only do it when there are two interface methods that have the same signature.
你错了。除了实现冲突的接口(interface)之外,选择显式接口(interface)实现的原因还有很多(例如隐藏 internal
接口(interface)的实现、实现类型理论不健全的旧/遗留接口(interface))兼容性原因(如 IList
),以及美观原因(减少 API 困惑,但应该使用 EditorBrowsable
)。
But for
public bool Contains(T item)
andpublic bool Contains(Object item)
, they are different methods because they have different signatures (generic parameter and non-generic parameter), soList
would have been implemented as...
在上面的段落中,我注意到 IList
是一个类型理论不健全接口(interface),即:它允许你做无意义和/或有害的事情,示例:
List<String> listOfString = new List<String>() { "a", "b", "c" };
IList asIList = listOfString;
asIList.Add( new Person() );
编译器会让这种情况发生,但它会在运行时崩溃,因为 List<String>
不能包含 Person
。由于 .NET 对协变和逆变的支持,这个问题可以通过具体化泛型解决(这就是为什么您可以安全地将任何 List<String>
隐式转换为 IEnumerable<Object>
,因为 String : Object
,即使 List<T>
确实如此)实际上没有实现 IEnumerable<Object>
,但它确实实现了 IEnumerable<T>
)。
Then why does List use an explicit interface method implementation to implement non-generic interface methods?
因为 IList
是一个糟糕的接口(interface),今天没有人应该使用它,但由于遗留兼容性要求,有些人被迫使用它。每个人都希望看到这些遗留接口(interface)消失(尤其是我自己),但我们不能,因为这会破坏二进制应用程序兼容性,而这对于任何运行时或平台在 SWE 生态系统中生存至关重要(这也是 .NET 团队不幸地拒绝许多有意义但会破坏现有编译程序的频繁请求(例如使 IList<T>
扩展 IReadOnlyList<T>
)。
I cannot see any benefit to use explicit interface method implementation in this scenario. Am I missing something here?
您遗漏了一些东西 - 我希望我的回答能够照亮您的想法。
关于c# - 为什么List使用显式接口(interface)方法实现来实现非泛型接口(interface)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66286379/