在.NET Core中进行编程时,我偶然发现了一个名为StringValues
的结构。它来自Microsoft.Extensions.Primitive
程序集,并保存在同一命名空间下。其源代码可在GitHub上找到。
我注意到它继承了一些接口:
IList<string>
ICollection<string>
IEnumerable<string>
IEnumerable
IReadOnlyList<string>
IReadOnlyCollection<string>
IEquatable<StringValues>
IEquatable<string>
IEquatable<string[]>
我想说,对于一个结构来说,这很多。当我查看其方法(在Visual Studio定义查看器中)时,我注意到它确实提供的很少。例如,我没有看到ICollection<T>
,Add()
或Clear()
的基本Remove()
方法。
当我尝试将StringValues
的实例强制转换为ICollection<string>
并使用Add()
时:
var stringValues = new StringValues("Foo");
var stringCollection = stringValues as ICollection<string>;
stringCollection.Add("Bar");
我最终在NotSupportedException
方法调用中抛出了Add()
:
NotSupportedException:不支持指定的方法。
所以我去了源代码(开源的无穷优势),看看发生了什么!然后我看到了:
void ICollection<string>.Add(string item)
{
throw new NotSupportedException();
}
void IList<string>.Insert(int index, string item)
{
throw new NotSupportedException();
}
bool ICollection<string>.Remove(string item)
{
throw new NotSupportedException();
}
void IList<string>.RemoveAt(int index)
{
throw new NotSupportedException();
}
void ICollection<string>.Clear()
{
throw new NotSupportedException();
}
这种编程方式有什么意义?尽管如此,我总是通过从接口继承来声明,可以将特定类型与继承的接口同等使用。
在这种情况下,似乎该结构不是要在公共场合使用?在查看已实现的Contains()
方法时会感到这种感觉,但仍然被标记为内部:
bool ICollection<string>.Contains(string item)
{
return IndexOf(item) >= 0;
}
答案 0 :(得分:3)
因为这样做通常有用,只要调用者仅调用可用方法即可。他们可以检查类似IList.IsReadOnly
之类的事物来预期这一点-如果返回false
,他们应该知道不要期望Add
等起作用。
将结构上不可变的类型传递给采用过去一直采用可变API的API的对象,例如IList
,因为同一个接口还提供了其他有用的功能
类似地,Stream
具有CanRead
和CanWrite
之类的东西,并且如果其中一个返回false
,则可以预期相应的读/写API会失败。