为什么List.Sort()是实例方法但Array.Sort()是静态的?

Dav*_*Lee 38 .net c#

我正在努力理解这部分语言背后的设计决策.我承认我对这一切都很陌生,但这最初引起了我的注意,我想知道我是否错过了一个明显的原因.请考虑以下代码:

List<int> MyList = new List<int>() { 5, 4, 3, 2, 1 };
int[] MyArray = {5,4,3,2,1};


//Sort the list
MyList.Sort();
//This was an instance method


//Sort the Array
Array.Sort(MyArray);
//This was a static method
Run Code Online (Sandbox Code Playgroud)

为什么它们不是以相同的方式实现 - 直观地说,如果它们都是实例方法会更有意义吗?

Han*_*ant 30

问题很有趣,因为它揭示了.NET类型系统的细节.与值类型,字符串和委托类型一样,数组类型在.NET中得到特殊处理.最值得注意的奇怪行为是您从未明确声明数组类型.编译器会为您提供充分的抖动帮助.System.Array是一种抽象类型,在编写代码的过程中,您将获得专用的数组类型.通过显式创建类型[]或使用在其基本实现中具有数组的泛型类.

在一个较大的程序中,拥有数百种阵列类型并不罕见.哪个没问题,但每种类型都有开销.它只是类型所需的存储,而不是它的对象.最大的一块是所谓的"方法表".简而言之,它是指向该类型的每个实例方法的指针列表.类加载器和抖动一起工作以填充该表.这通常称为"v-table",但不是很匹配,该表包含指向非虚拟和虚拟方法的指针.

你可以看到这可能导致的地方,设计师担心有很多类型的大方法表.所以寻找减少开销的方法.

Array.Sort()是一个明显的目标.

同一问题与泛型类型无关.泛型的一个很好的,很多,一个方法表中的一个可以处理引用类型的任何类型参数的方法指针.

  • @Bevan - Kudos注意到差异,但非虚方法确实在方法表中占用了一个插槽.它是C#和Java之间经常引用的差异,但实际上并非如此.他们甚至通过虚拟呼叫进行呼叫,在此博客文章中有记录:http://blogs.msdn.com/b/ericgu/archive/2008/07/02/why-does-c-always-use-callvirt.aspx此外,该表不存在于GC内存中,它存储在加载器堆中.它只能通过卸载appdomain来释放. (6认同)
  • 我从未见过有人用"抖动"这个词来描述除了早晨咖啡因以外的任何东西.你是否将JIT缩写为JITer(即时编译器)? (2认同)
  • 我不确定.非虚方法不占用方法表中的空间(它们仅用于支持多态分派),因此不需要切换到静态方法来节省内存.另外,我们谈论(最坏的情况下)几千字节的内存 - 如果这是一个问题,他们将永远不会实现垃圾收集. (2认同)

Ava*_*vra 5

您正在比较两种不同类型的"对象容器":

MyList是类型为List的通用集合,类型为包装类int,其中List<T>表示强类型的对象列表.List类本身提供了搜索,排序和操作其包含对象的方法.

MyArrayArray类型的基本数据结构.Array不提供与List相同的丰富方法.阵列可以同时是单维的,多维的或锯齿状的,而开箱即用的列表只是单维的.

看看这个问题,它提供了有关这些数据类型的更丰富的讨论: Array versus List<T>: When to use which?

  • @StriplingWarrior:实际上排序可以/将使用*完全*相同的代码... (2认同)
  • @StriplingWarrior`List.Sort`在内部调用`Array.Sort` (2认同)