泛型接口继承(设计问题)

本文关键字:问题 继承 泛型接口 | 更新日期: 2023-09-27 18:32:38

我有两个接口; ISetISet<T>

两者都实现了Add,Move和Clear,但具有不同的参数类型; object和T。

现在我有两个选择。要么让ISet<T>继承ISet,要么让它们彼此隔离。

当然,ISet<T>继承ISet的一大好处是,无论我需要ISet,我总是可以在任何需要ISet<T>的地方使用。但这样做我还必须使用 T 参数向成员添加"new"修饰符。我不太喜欢"新"修饰符,但在这种情况下,maybee 这是更好的选择吗?

有一个不是ISetISet<T>感觉很奇怪.这是合乎逻辑的假设。我真的不能确切地说出为什么我不喜欢"新"修饰符。就像"goto"关键字一样。我只是尽量不使用它。

你认为我应该在这里做什么?继承与否?


在 .NET 中,我们有不继承ICollection<T>ICollectionIList<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();
}