C# 为什么不是';数组是否为泛型类型?

C# 为什么不是';数组是否为泛型类型?,c#,generics,types,language-design,C#,Generics,Types,Language Design,数组声明为: public abstract class Array : ICloneable, IList, ICollection, IEnumerable { 我想知道为什么不是: public partial class Array<T> : ICloneable, IList<T>, ICollection<T>, IEnumerable<T> { 公共部分类数组 :ICloneable、IList、ICollecti

数组
声明为:

public abstract class Array
    : ICloneable, IList, ICollection, IEnumerable {
我想知道为什么不是:

public partial class Array<T>
    : ICloneable, IList<T>, ICollection<T>, IEnumerable<T> {
公共部分类数组
:ICloneable、IList、ICollection、IEnumerable{
  • 如果将其声明为泛型类型,会出现什么问题

  • 如果它是泛型类型,我们是否仍然需要非泛型类型,或者它是否可以从
    数组
    派生?例如

    public partial class Array: Array<object> { 
    
    公共部分类数组:数组{
    

  • Array是一种历史类型,可以追溯到没有泛型的时候

    今天,让
    数组
    ,然后是
    数组
    ,然后是特定的类;)是有意义的

    因此,我想知道为什么不是:

    原因是C#的第一个版本中没有泛型

    但我自己也不知道问题出在哪里

    问题是它会破坏大量使用
    数组
    类的代码。C#不支持多重继承,所以像这样的行

    Array ary = Array.Copy(.....);
    int[] values = (int[])ary;
    
    会被打破的


    如果微软从头开始重新制作C#和.NET,那么将
    Array
    制作成一个泛型类可能没有问题,但事实并非如此。

    [Update,new insights,它觉得到目前为止缺少了一些东西]

    关于先前的答复:

    • 数组和其他类型一样是协变的。你可以用协变实现像“object[]foo=new string[5];”这样的东西,所以这不是原因
    • 兼容性可能是不重新考虑设计的原因,但我认为这也不是正确的答案
    然而,我能想到的另一个原因是,数组是内存中一组线性元素的“基本类型”。我一直在考虑使用数组,这就是为什么T是一个对象,为什么这个“对象”会存在的原因。在这个场景中,T[]正是我认为数组的另一种语法,它与数组是协变的。由于类型实际上不同,所以我认为这两种情况类似。

    注意,基本对象和基本数组都不是面向对象语言的要求。C++是这个例子的完美例子。没有这些基本构造的基本类型的警告不能使用反射来使用数组或对象。对于那些用来制作对象的对象,使对象“感觉自然”。事实上,没有数组基类同样不可能实现Foo——Foo虽然使用频率不高,但对范例来说同样重要

    因此,在没有数组基类型但有丰富的运行时类型(特别是反射)的情况下使用C#是不可能的

    所以更多的细节

    在哪里使用数组以及为什么使用数组

    对于数组这样的基本类型,有一个基本类型用于很多事情,这是有充分理由的:

    • 简单数组
    是的,我们已经知道人们使用
    T[]
    ,就像他们使用
    List
    一样。确切地说,两者都实现了一组通用的接口:
    IList
    ICollection
    IEnumerable
    IList
    ICollection
    IEnumerable

    如果你知道这一点,你可以很容易地创建一个数组。我们也都知道这是真的,这并不令人兴奋,所以我们继续

    • 创建收藏。
    若你们深入研究这个列表,你们最终会得到一个数组——确切地说:一个T[]数组

    那为什么呢?虽然你可以使用指针结构(LinkedList),只是不一样。列表是连续的内存块,它们的速度是通过连续的内存块来实现的。这有很多原因,但简单地说:处理连续内存是处理内存的最快方式,甚至在CPU中也有相应的指令,使其更快

    仔细的读者可能会指出这样一个事实,即您不需要数组,但IL可以理解并处理类型为“t”的连续元素块。换句话说,您可以在这里去掉数组类型,只要您确保IL可以使用另一种类型来做同样的事情

    请注意,存在值和类类型。为了保持最佳性能,您需要将它们存储在块中……但对于编组来说,这只是一个要求

    • 编组。
    编组使用所有语言都同意的基本类型进行通信。这些基本类型包括字节、整数、浮点、指针…和数组。最值得注意的是C/C++中使用数组的方式,如下所示:

    for (Foo *foo = beginArray; foo != endArray; ++foo) 
    {
        // use *foo -> which is the element in the array of Foo
    }
    
    array.GetType().GetMethod("GetLength").Invoke(array, 0); // don't...
    
    ((Array)someArray).GetLength(0); // do!
    
    基本上,这会在数组的开始处设置一个指针,并递增指针(使用sizeof(Foo)字节),直到它到达数组的结尾。元素在*Foo处检索,它获取指针“Foo”指向的元素

    请再次注意,有值类型和引用类型。您真的不希望MyArray将所有内容都存储为一个对象。实现MyArray要复杂得多

    一些细心的读者可以在这里指出一个事实,这里并不真正需要数组,这是真的。你需要一个Foo类型的连续元素块,如果它是值类型,它必须作为值类型的(字节表示)存储在块中

    • 多维数组
    那么更多…关于多维性呢?显然规则不是那么黑和白,因为突然我们不再有所有的基类了:

    int[,] foo2 = new int[2, 3];
    foreach (var type in foo2.GetType().GetInterfaces())
    {
        Console.WriteLine("{0}", type.ToString());
    }
    
    Strong type刚从窗口消失,你最终得到了集合类型
    IList
    ICollection
    IEnumerable
    。嘿,那么我们应该如何获得大小呢?当使用数组基类时,我们可以
    ((Array)someArray).GetLength(0); // do!
    
    Mammoth[] mammoths = new Mammoth[10];
    Animal[] animals = mammoths;            // Covariant conversion
    animals[1] = new Giraffe();             // Run-time exception
    
    Array<Mammoth> mammoths = new Array<Mammoth>(10);
    Array<Animal> animals = mammoths;           // Not allowed.
    IEnumerable<Animals> animals = mammoths;    // Covariant conversion
    
    ICollection<Mammoth> collection = new Mammoth[10];  // Cast to interface type
    collection.Add(new Mammoth());                      // Run-time exception
    
    ICollection<Mammoth> mammoths = new Array<Mammoth>(10);
    ICollection<Animal> animals = mammoths;     // Not allowed
    
    interface IList<out T> : ICollection<T>
    {
        T this[int index] { get; }
        int IndexOf(object value);
    }
    
    interface ICollection<out T> : IEnumerable<T>
    {
        int Count { get; }
        bool Contains(object value);
    }
    
    Array<Mammoth> mammoths = new Array<Mammoth>(10);
    IList<Animals> animals = mammoths;    // Covariant conversion