泛型接口继承(设计问题)
本文关键字:问题 继承 泛型接口 | 更新日期: 2023-09-27 18:32:38
我有两个接口; ISet
和ISet<T>
两者都实现了Add,Move和Clear,但具有不同的参数类型; object和T。
现在我有两个选择。要么让ISet<T>
继承ISet
,要么让它们彼此隔离。
当然,ISet<T>
继承ISet
的一大好处是,无论我需要ISet
,我总是可以在任何需要ISet<T>
的地方使用。但这样做我还必须使用 T 参数向成员添加"new"修饰符。我不太喜欢"新"修饰符,但在这种情况下,maybee 这是更好的选择吗?
有一个不是ISet
的ISet<T>
感觉很奇怪.这是合乎逻辑的假设。我真的不能确切地说出为什么我不喜欢"新"修饰符。就像"goto"关键字一样。我只是尽量不使用它。
你认为我应该在这里做什么?继承与否?
在 .NET 中,我们有不继承ICollection<T>
和ICollection
。IList<T>
也没有,IList
.但IEnumerable<T>
继承自IEnumerable
.
我知道 ISet 接口已经存在(这只是一个例子(
我在其他情况下也遇到过这个问题。我通常通过让ISet<T>
拥有其方法版本来解决它,并且ISet
有自己的例外对象。正如你提到的。除此之外,我还创建了一个名为 BaseSet<T>
的抽象类,它实现了ISet<T>
和ISet
,如下所示
public abstract class BaseSet<T> : ISet<T>, ISet {
public abstract void Add<T>(T item);
void ISet.Add(object item) {
this.Add((T)item);
}
}
然后,只需从BaseSet<T>
继承并实现最常见场景的ISet<T>
接口,但如果BaseSet<T>
方便类不适合他们需要,他们仍然可以完全实现ISet<T>
和ISet
。它还消除了使用 new
关键字的需要。
从非泛型形式继承的唯一真正能让你买到的是能够在ISet<T>
上执行某些操作,而不必在编译时知道T
是什么。 不能以类型安全的方式将项添加到这样的集合中,并且读取可能有些低效(因为必须对值类型进行装箱(,但像Count
这样的方法或属性可能非常有用。
我的建议是你定义多个接口,就像这样(请注意,我正在添加一些你没有的成员,因为你的集合目前是只写的,因此不是很有用(
interface ICountable { int Count {get;} }interface IClearable { int Count {get;} }interface IAppendable: IConvertableToEnumerable, ICountable {IEnumerable CopyAsEnumerable((;}interface IFetchable 最好 遵循通用的 .NET paradim,但你总是可以反过来考虑这样做吗?
interface ISet : ISet<object> { } interface ISet<T> { void Add<T>(T item); void Clear(); void Remove<T>(T item); }
如果它是你正在实现的集合,是否可以在 .NET 中使用替代集合?
如果你想将它与任何类型一起使用,为什么不直接使用 ISet 并提供 Object 作为 T?
,如果你的问题域需要一个泛型,那么从非泛型派生并不一定能给你带来任何东西。在类型安全版本中允许对象是否有潜在的副作用?如果是这样,在我看来,这至少是泛型旨在克服的问题的一方......
为什么你有一个非泛型ISet
? .NET 支持泛型,几乎没有理由不使用它们。我相信所有 .NET 语言都完全支持泛型。
是的,.NET 库既有IList
,也有IList<T>
。但是,我相信这样做的原因是历史的,从 .NET 有泛型之前开始。如果从一开始就实施通用支持,我认为IList
不会存在,只有IList<T>
会存在。
原因很简单,为什么IEnumerable<T>
继承自IEnumerable
。它的名称是 foreach 语句,它仅适用于集合类型。任何集合类型都应该实现非泛型接口IEnumerable
(甚至数组也实现它(。以下是每个场景背后发生的事情:
E enumerator = (collection).GetEnumerator(); // non-generic interface
try {
while (enumerator.MoveNext()) { // enumerator also non-generic
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
因此,我们有从非泛型继承的泛型接口,以允许在 foreach 语句中使用泛型集合。另一种选择是更改编译器:)
没有核心的 .net 功能,这些功能依赖于IList
接口。因此,我们有两个独立的接口 - 通用和非通用。
在您的情况下,我认为没有任何理由创建非通用接口ISet
.如果你想要一个接受具有不同类型参数的泛型ISet<T>
的方法,那么只需创建接受泛型ISet<T>
的泛型方法:
public void Foo<T>(ISet<T> set)
{
set.Bar();
}