为什么List要使用显式接口方法实现来实现非泛型接口方法?
Why does List use an explicit interface method implementation to implement non-generic interface methods?
// 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
使用显式接口方法实现(显式指定接口名称)来实现非泛型Contains
。但是我对显式接口方法实现的了解是,只有当有两个具有相同签名的接口方法时才这样做。
但对于 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要使用显式接口方法实现来实现非泛型接口方法呢?我看不出在这种情况下使用显式接口方法实现有任何好处。我在这里遗漏了什么吗?
You can see that List
uses explicit interface method implementation (explicitly specify the interface's name) to implement the non-generic Contains
确实如此。
但那是因为 IList
接口(而不是 IList<T>
)已有数十年的历史 - 从 .NET 支持泛型(.NET 1.0 于 2001 年推出)之前的原始、黑暗时代开始- 直到 2005 年的 .NET Framework 2.0 才添加泛型)。那真是一个被上帝遗弃的时代。
List<T>
(但不是 IList<T>
)实现了 IList
接口,以便接受 [=15= 的旧代码可以使用新的通用 List<T>
](以一种允许保留对象身份并且不需要分配单独的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.
你错了。除了实现冲突的接口(例如隐藏 internal
接口的实现,实现类型理论 不合理的接口实现之外,还有 许多原因 选择显式接口实现 older/legacy 出于兼容性原因(如 IList
)和美学原因(减少 API 混乱,尽管 EditorBrowsable
应该 用于此)。
But for public bool Contains(T item)
and public bool Contains(Object item)
, they are different methods because they have different signatures (generic parameter and non-generic parameter), so List
would have been implemented as...
在上面的段落中,我注意到 IList
是一个 type-theoretic unsound 接口,即:它允许你做毫无意义的事情and/or有害的东西,例如:
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
是一个糟糕的界面,今天没有人应该使用它,但有些人 were/are 由于旧版兼容性而被迫使用它要求。每个人都希望看到这些遗留接口消失(尤其是我自己),但我们不能,因为它会破坏二进制应用程序的兼容性,这对于任何运行时或平台在 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?
您 遗漏了一些东西 - 我希望我的回答能启发您的想法。
// 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
使用显式接口方法实现(显式指定接口名称)来实现非泛型Contains
。但是我对显式接口方法实现的了解是,只有当有两个具有相同签名的接口方法时才这样做。
但对于 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要使用显式接口方法实现来实现非泛型接口方法呢?我看不出在这种情况下使用显式接口方法实现有任何好处。我在这里遗漏了什么吗?
You can see that
List
uses explicit interface method implementation (explicitly specify the interface's name) to implement the non-genericContains
确实如此。
但那是因为 IList
接口(而不是 IList<T>
)已有数十年的历史 - 从 .NET 支持泛型(.NET 1.0 于 2001 年推出)之前的原始、黑暗时代开始- 直到 2005 年的 .NET Framework 2.0 才添加泛型)。那真是一个被上帝遗弃的时代。
List<T>
(但不是 IList<T>
)实现了 IList
接口,以便接受 [=15= 的旧代码可以使用新的通用 List<T>
](以一种允许保留对象身份并且不需要分配单独的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.
你错了。除了实现冲突的接口(例如隐藏 internal
接口的实现,实现类型理论 不合理的接口实现之外,还有 许多原因 选择显式接口实现 older/legacy 出于兼容性原因(如 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
是一个 type-theoretic unsound 接口,即:它允许你做毫无意义的事情and/or有害的东西,例如:
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
是一个糟糕的界面,今天没有人应该使用它,但有些人 were/are 由于旧版兼容性而被迫使用它要求。每个人都希望看到这些遗留接口消失(尤其是我自己),但我们不能,因为它会破坏二进制应用程序的兼容性,这对于任何运行时或平台在 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?
您 遗漏了一些东西 - 我希望我的回答能启发您的想法。