为什么派生列表<;T>;类只是为了重述索引器

本文关键字:索引 列表 派生 lt 为什么 gt | 更新日期: 2023-09-27 18:28:20

我一直看到List派生类看起来像这个

class MyClassList : List<MyClass>
{
    public MyClass this[int index]
    {
        get { return (MyClass)base[index]; }
    }
}

这种继承有什么意义?看起来它只是重申了成员的选角。我可以理解其他类型的索引器,但这只是对默认List索引器的重述,并引发Visual Studio警告RE:隐藏基本索引器。这样做是对还是错,为什么?

为什么派生列表<;T>;类只是为了重述索引器

也许通过索引器来防止覆盖值是一个非常糟糕的尝试?

MyClassList x = new MyClassList();
x.Add(new MyClass());
x[0] = new MyClass(); // Error!

当然,这并不能阻止:

List<MyClass> x = new MyClassList();
x.Add(new MyClass());
x[0] = new MyClass(); // No problem here...

基本上,这是个坏主意。不幸的是,糟糕的代码比比皆是——不要仅仅从存在中推断有用性:(

没有充分的理由。它隐藏基本索引器,而不是覆盖它,这可能很危险,而且根本没有任何效果。

在大多数情况下,最好只是直接使用List<MyClass>。如果您根本不打算扩展List<>的功能,那么就没有必要为此创建一个特殊的类。

我认为这样做没有任何用处。此外,铸造是不必要的。

我认为应该隐藏基类的set访问器,使其看起来像索引器是只读的。但它没用,因为它很容易解决:

MyClassList list = ...
((List<MyClass>)list)[index] = value;

无论如何,List<T>类不是为继承而设计的。如果需要创建专用集合,请改为从Collection<T>继承。

我以前见过这种类型的东西,人们想把它串行化为另一种类型,现在如果这是其中唯一的代码,并且由于其他原因不需要是MyClassList类型,那就完全没有意义了。

这基本上是一个尝试来正确覆盖[]List的访问,以实现一些自定义元素访问逻辑。

值得注意的是,提供的代码是不好的,如果不仅仅是危险的话。如果你想用列表做一些棘手的事情,不要覆盖(或倾向于这样做)[],而是为此实现一些自定义方法。

我的猜测是,代码试图表现为只读List。无法通过索引写入MyClassList<T>类型变量的项,尽管可以将其强制转换回List<T>并以这种方式写入变量。有时,让一个类型能力有限的变量保持一个实际能力更大的对象是有意义的。然而,实现这一点的正确方法通常是使用接口,一个主要的例子是IEnumerable<T>。如果List<T>被传递给接受类型为IEnumerable<T>的参数的例程,则该例程可以将其参数强制转换回List<T>,并使用Add()Remove()等成员,但接受类型为IEnumerable<T>的参数的必须例程不会尝试将其用作其他任何参数。

原始海报显示的代码风格的一个主要问题是,更"强大"的方向是基础,而不是派生类型。因为List<T>派生自IEnumerable<T>,这意味着List<T>的所有实例都可以枚举,但不仅仅是一些可枚举的东西在List<T>中具有额外的功能。相反,在实现类时,每个MyClassList<T>都可以被读取和写入,但只有List<T>的一些实例可以用作MyClassList<T>