一時好奇心起,想一窺.Net Framework 4.0內部究竟是使用何種算法排序。以前聽人說Framework內部是使用的快速排序,但究竟耳聽為虛,眼見為實。主要通過JetBrains dotPeek 1.2作為工具反編譯Framework的代碼進行查看,也參考了其他很多資料。本人才疏學淺,其中難免存在錯誤,希望大家不吝指教。
眾所周知,數組實質上是Array類的實例。呃,要是被代表了,可以通過如下方式驗證:
重載方法包含的參數有:
這一系列共有4個方法:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public static void Sort(Array array)
{
if (array == null)
throw new ArgumentNullException("array");
Array.Sort(array, null, array.GetLowerBound(0), array.Length, null);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static void Sort(Array array, int index, int length)
{
Array.Sort(array, null, index, length, null);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public static void Sort(Array array, IComparer comparer)
{
if (array == null)
throw new ArgumentNullException("array");
Array.Sort(array, null, array.GetLowerBound(0), array.Length, comparer);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static void Sort(Array array, int index, int length, IComparer comparer)
{
Array.Sort(array, null, index, length, comparer);
}
比較這4個方法,發現其歸根到底都調用了非泛型不帶關鍵字數組排序方法:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecuritySafeCritical]
public static void Sort(Array keys, Array items, int index, int length, IComparer comparer)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (keys.Rank != 1 || items != null && items.Rank != 1)
throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
if (items != null && keys.GetLowerBound(0) != items.GetLowerBound(0))
throw new ArgumentException(Environment.GetResourceString("Arg_LowerBoundsMustMatch"));
if (index < keys.GetLowerBound(0) || length < 0)
throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (keys.Length - (index - keys.GetLowerBound(0)) < length || items != null && index - items.GetLowerBound(0) > items.Length - length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (length <= 1 || (comparer == Comparer.Default || comparer == null) && Array.TrySZSort(keys, items, index, index + length - 1))
return;
object[] keys1 = keys as object[];
object[] items1 = null;
if (keys1 != null)
items1 = items as object[];
if (keys1 != null && (items == null || items1 != null))
new Array.SorterObjectArray(keys1, items1, comparer).Sort(index, length);
else
new Array.SorterGenericArray(keys, items, comparer).Sort(index, length);
}
閱讀代碼,我們可以發現會首先嘗試Array的TrySZSort方法,成功則直接返回。接著當關鍵字數組為object[]且項數組為空或項數組也為object[]時,將會調用SorterObjectArray的排序方法,否則調用SorterGenericArray的排序方法
TrySZSort的方法代碼如下:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail), SecurityCritical] [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool TrySZSort(Array keys, Array items, int left, int right);
可以發現該方法由CLR內部實現,但是好在現在CoreCLR已經開源了,我們可以通過CoreCLR大致了解到這個函數是做什麼的。經過查找,發現在一個名叫ArrayHelper的類中發現該發現,代碼如下:
FCIMPL4(FC_BOOL_RET, ArrayHelper::TrySZSort, ArrayBase * keys, ArrayBase * items, UINT32 left, UINT32 right)
FCALL_CONTRACT;
VALIDATEOBJECT(keys);
VALIDATEOBJECT(items);
_ASSERTE(keys != NULL);
// <TODO>@TODO: Eventually, consider adding support for single dimension arrays with
// non-zero lower bounds. VB might care. </TODO>
if (keys->GetRank() != 1 || keys->GetLowerBoundsPtr()[0] != 0)
FC_RETURN_BOOL(FALSE);
_ASSERTE(left <= right);
_ASSERTE(right < keys->GetNumComponents() || keys->GetNumComponents() == 0);
TypeHandle keysTH = keys->GetArrayElementTypeHandle();
const CorElementType keysElType = keysTH.GetVerifierCorElementType();
if (!CorTypeInfo::IsPrimitiveType_NoThrow(keysElType))
FC_RETURN_BOOL(FALSE);
if (items != NULL) {
TypeHandle itemsTH = items->GetArrayElementTypeHandle();
if (keysTH != itemsTH)
FC_RETURN_BOOL(FALSE); // Can't currently handle sorting different types of arrays.
}
// Handle special case of a 0 element range to sort.
// Consider both Sort(array, x, x) and Sort(zeroLen, 0, zeroLen.Length-1);
if (left == right || right == 0xffffffff)
FC_RETURN_BOOL(TRUE);
switch(keysElType) {
case ELEMENT_TYPE_I1:
ArrayHelpers<I1>::IntrospectiveSort((I1*) keys->GetDataPtr(), (I1*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_BOOLEAN:
ArrayHelpers<U1>::IntrospectiveSort((U1*) keys->GetDataPtr(), (U1*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_I2:
ArrayHelpers<I2>::IntrospectiveSort((I2*) keys->GetDataPtr(), (I2*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_CHAR:
ArrayHelpers<U2>::IntrospectiveSort((U2*) keys->GetDataPtr(), (U2*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_I4:
ArrayHelpers<I4>::IntrospectiveSort((I4*) keys->GetDataPtr(), (I4*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_U4:
ArrayHelpers<U4>::IntrospectiveSort((U4*) keys->GetDataPtr(), (U4*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_R4:
{
R4 * R4Keys = (R4*) keys->GetDataPtr();
R4 * R4Items = (R4*) (items == NULL ? NULL : items->GetDataPtr());
// Comparison to NaN is always false, so do a linear pass
// and swap all NaNs to the front of the array
left = ArrayHelpers<R4>::NaNPrepass(R4Keys, R4Items, left, right);
if(left != right) ArrayHelpers<R4>::IntrospectiveSort(R4Keys, R4Items, left, right);
break;
};
case ELEMENT_TYPE_I8:
ArrayHelpers<I8>::IntrospectiveSort((I8*) keys->GetDataPtr(), (I8*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_U8:
ArrayHelpers<U8>::IntrospectiveSort((U8*) keys->GetDataPtr(), (U8*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break;
case ELEMENT_TYPE_R8:
{
R8 * R8Keys = (R8*) keys->GetDataPtr();
R8 * R8Items = (R8*) (items == NULL ? NULL : items->GetDataPtr());
// Comparison to NaN is always false, so do a linear pass
// and swap all NaNs to the front of the array
left = ArrayHelpers<R8>::NaNPrepass(R8Keys, R8Items, left, right);
if(left != right) ArrayHelpers<R8>::IntrospectiveSort(R8Keys, R8Items, left, right);
break;
};
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
// In V1.0, IntPtr & UIntPtr are not fully supported types. They do
// not implement IComparable, so searching & sorting for them should
// fail. In V1.1 or V2.0, this should change.
FC_RETURN_BOOL(FALSE);
default:
_ASSERTE(!"Unrecognized primitive type in ArrayHelper::TrySZSort");
FC_RETURN_BOOL(FALSE);
}
FC_RETURN_BOOL(TRUE);
FCIMPLEND
大致可以看出,該方法的作用是對Framework的基本類型進行排序,排序也使用了內省排序。內省排序詳見後面。
我們來看一下SorterObjectArray的構造函數及Sort方法:
private object[] keys;
private object[] items;
private IComparer comparer;
internal SorterObjectArray(object[] keys, object[] items, IComparer comparer)
{
if (comparer == null)
{
comparer = Comparer.Default;
}
this.keys = keys;
this.items = items;
this.comparer = comparer;
}
構造函數很簡單,僅僅賦值字段
internal void Sort(int left, int length)
{
if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
{
this.IntrospectiveSort(left, length);
return;
}
this.DepthLimitedQuickSort(left, length + left - 1, 32);
}
初看一下代碼 ,發現關鍵語句是BinaryCompatibility.TargetsAtLeast_Desktop_V4_5,其決定了究竟使用了哪種排序方式。從字面意思上是說是否為桌面版本4.5及以上,經過驗證後也確實如此,但因為與主題關系不大,就不細說,僅簡單說下原理。
編譯器在編譯程序集時,會加上TargetFramework特性,.Network Framework通過檢測該特性來確定框架版本,如下是4.0的一個程序集示例:
private void DepthLimitedQuickSort(int left, int right, int depthLimit)
{
do
{
if (depthLimit == 0)
{
try
{
this.Heapsort(left, right);
break;
}
catch (IndexOutOfRangeException)
{
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[]
{
this.comparer
}));
}
catch (Exception innerException)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException);
}
}
int num = left;
int num2 = right;
int median = Array.GetMedian(num, num2);
try
{
this.SwapIfGreaterWithItems(num, median);
this.SwapIfGreaterWithItems(num, num2);
this.SwapIfGreaterWithItems(median, num2);
}
catch (Exception innerException2)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException2);
}
object obj = this.keys[median];
do
{
try
{
while (this.comparer.Compare(this.keys[num], obj) < 0)
{
num++;
}
while (this.comparer.Compare(obj, this.keys[num2]) < 0)
{
num2--;
}
}
catch (IndexOutOfRangeException)
{
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[]
{
this.comparer
}));
}
catch (Exception innerException3)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException3);
}
if (num > num2)
{
break;
}
if (num < num2)
{
object obj2 = this.keys[num];
this.keys[num] = this.keys[num2];
this.keys[num2] = obj2;
if (this.items != null)
{
object obj3 = this.items[num];
this.items[num] = this.items[num2];
this.items[num2] = obj3;
}
}
num++;
num2--;
}
while (num <= num2);
depthLimit--;
if (num2 - left <= right - num)
{
if (left < num2)
{
this.DepthLimitedQuickSort(left, num2, depthLimit);
}
left = num;
}
else
{
if (num < right)
{
this.DepthLimitedQuickSort(num, right, depthLimit);
}
right = num2;
}
}
while (left < right);
}
調用時深度為32,每調用一次,深度減1,深度大於0時使用快速排序,當深度為0時即轉入堆排序。在使用快速排序時,選取首、尾和首尾中間三個索引中取值為中間的對象作為主元。然後取左右兩邊較長的序列進入下一輪快速排序。
用到的其余代碼如下:
internal void SwapIfGreaterWithItems(int a, int b)
{
if (a != b && this.comparer.Compare(this.keys[a], this.keys[b]) > 0)
{
object obj = this.keys[a];
this.keys[a] = this.keys[b];
this.keys[b] = obj;
if (this.items != null)
{
object obj2 = this.items[a];
this.items[a] = this.items[b];
this.items[b] = obj2;
}
}
}
private void Swap(int i, int j)
{
object obj = this.keys[i];
this.keys[i] = this.keys[j];
this.keys[j] = obj;
if (this.items != null)
{
object obj2 = this.items[i];
this.items[i] = this.items[j];
this.items[j] = obj2;
}
}
private void Heapsort(int lo, int hi)
{
int num = hi - lo + 1;
for (int i = num / 2; i >= 1; i--)
{
this.DownHeap(i, num, lo);
}
for (int j = num; j > 1; j--)
{
this.Swap(lo, lo + j - 1);
this.DownHeap(1, j - 1, lo);
}
}
private void DownHeap(int i, int n, int lo)
{
object obj = this.keys[lo + i - 1];
object obj2 = (this.items != null) ? this.items[lo + i - 1] : null;
while (i <= n / 2)
{
int num = 2 * i;
if (num < n && this.comparer.Compare(this.keys[lo + num - 1], this.keys[lo + num]) < 0)
{
num++;
}
if (this.comparer.Compare(obj, this.keys[lo + num - 1]) >= 0)
{
break;
}
this.keys[lo + i - 1] = this.keys[lo + num - 1];
if (this.items != null)
{
this.items[lo + i - 1] = this.items[lo + num - 1];
}
i = num;
}
this.keys[lo + i - 1] = obj;
if (this.items != null)
{
this.items[lo + i - 1] = obj2;
}
}
IntrospectiveSort的代碼如下:
private void IntrospectiveSort(int left, int length)
{
if (length < 2)
{
return;
}
try
{
this.IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(this.keys.Length));
}
catch (IndexOutOfRangeException)
{
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(this.comparer);
}
catch (Exception innerException)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException);
}
}
private void IntroSort(int lo, int hi, int depthLimit)
{
while (hi > lo)
{
int num = hi - lo + 1;
if (num <= 16)
{
if (num == 1)
{
return;
}
if (num == 2)
{
this.SwapIfGreaterWithItems(lo, hi);
return;
}
if (num == 3)
{
this.SwapIfGreaterWithItems(lo, hi - 1);
this.SwapIfGreaterWithItems(lo, hi);
this.SwapIfGreaterWithItems(hi - 1, hi);
return;
}
this.InsertionSort(lo, hi);
return;
}
else
{
if (depthLimit == 0)
{
this.Heapsort(lo, hi);
return;
}
depthLimit--;
int num2 = this.PickPivotAndPartition(lo, hi);
this.IntroSort(num2 + 1, hi, depthLimit);
hi = num2 - 1;
}
}
}
private int PickPivotAndPartition(int lo, int hi)
{
int num = lo + (hi - lo) / 2;
this.SwapIfGreaterWithItems(lo, num);
this.SwapIfGreaterWithItems(lo, hi);
this.SwapIfGreaterWithItems(num, hi);
object obj = this.keys[num];
this.Swap(num, hi - 1);
int i = lo;
int num2 = hi - 1;
while (i < num2)
{
while (this.comparer.Compare(this.keys[++i], obj) < 0)
{
}
while (this.comparer.Compare(obj, this.keys[--num2]) < 0)
{
}
if (i >= num2)
{
break;
}
this.Swap(i, num2);
}
this.Swap(i, hi - 1);
return i;
}
在其中用到的FloorLog2代碼如下:
internal static int FloorLog2(int n)
{
int num = 0;
while (n >= 1)
{
++num;
n /= 2;
}
return num;
}
其余用到的方法請參見上面的DepthLimitedQuickSort,初始深度為長度的2的對數取下界的2倍,其流程圖如下:
[SecuritySafeCritical]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
{
if (array == null)
throw new ArgumentNullException("array");
if (index < 0 || length < 0)
throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - index < length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (length <= 1 || (comparer == null || comparer == Comparer<T>.Default) && Array.TrySZSort((Array) array, (Array) null, index, index + length - 1))
return;
ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
}
查看ArraySortHelper<T>代碼,發現該類代碼也與泛型不帶關鍵字數組排序方法邏輯完全一致,就不再細說了。
泛型帶關鍵字數組排序方法共4個,而最終調用的是public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)這個方法。該方法如下:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecuritySafeCritical]
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (index < 0 || length < 0)
throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (keys.Length - index < length || items != null && index > items.Length - length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (length <= 1 || (comparer == null || comparer == Comparer<TKey>.Default) && Array.TrySZSort((Array) keys, (Array) items, index, index + length - 1))
return;
if (items == null)
Array.Sort<TKey>(keys, index, length, comparer);
else
ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
}
該方法在items為空時直接調用泛型帶關鍵字數組排序方法,在其他情況下調用ArraySortHelper<TKey, TValue>的排序方法。
查看ArraySortHelper<TKey, TValue>的代碼,發現該類代碼也與泛型帶關鍵字數組排序方法邏輯完全一致,就不再細說了。
ArrayList這貨雖然現在很少用了,但是畢竟了曾風光了一段時間,還是提一下,通過查看其代碼,發現底層還是調用的Array的非泛型不帶關鍵字數組的排序方法。這也不奇怪,跟List一樣,底層用的都是數組。
public virtual void Sort(int index, int count, IComparer comparer)
{
if (index < 0)
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (this._size - index < count)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
}
Array.Sort(this._items, index, count, comparer);
this._version++;
}
跟ArrayList類似,其底層調用的是Array的泛型不帶關鍵字數組的排序方法。代碼如下:
public void Sort(int index, int count, IComparer<T> comparer)
{
if (index < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
if (count < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
if (this._size - index < count)
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
Array.Sort<T>(this._items, index, count, comparer);
++this._version;
}
[__DynamicallyInvokable]
public void Sort(Comparison<T> comparison)
{
if (comparison == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
if (this._size <= 0)
return;
Array.Sort<T>(this._items, 0, this._size, (IComparer<T>) new Array.FunctorComparer<T>(comparison));
}
通過查看代碼,發現OrderBy與OrderByDescending基本一致,都使用了OrderedEnumerable<TSource, TKey>類,代碼如下:
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, (IComparer<TKey>) null, false);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, false);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, (IComparer<TKey>) null, true);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, true);
}
而OrderedEnumerable<TSource, TKey>繼承自OrderedEnumerable<TElement>,OrderedEnumerable<TSource, TKey>中排序使用了EnumerableSorter<TElement, TKey>,而EnumerableSorter<TElement, TKey>繼承自EnumerableSorter<TElement>。在EnumerableSorter<TElement>我們可以發現排序的關鍵代碼:
internal int[] Sort(TElement[] elements, int count)
{
this.ComputeKeys(elements, count);
int[] map = new int[count];
for (int index = 0; index < count; ++index)
map[index] = index;
this.QuickSort(map, 0, count - 1);
return map;
}
private void QuickSort(int[] map, int left, int right)
{
do
{
int left1 = left;
int right1 = right;
int index1 = map[left1 + (right1 - left1 >> 1)];
while (true)
{
do
{
if (left1 >= map.Length || this.CompareKeys(index1, map[left1]) <= 0)
{
while (right1 >= 0 && this.CompareKeys(index1, map[right1]) < 0)
--right1;
if (left1 <= right1)
{
if (left1 < right1)
{
int num = map[left1];
map[left1] = map[right1];
map[right1] = num;
}
++left1;
--right1;
}
else
break;
}
else
goto label_1;
}
while (left1 <= right1);
break;
label_1:
++left1;
}
if (right1 - left <= right - left1)
{
if (left < right1)
this.QuickSort(map, left, right1);
left = left1;
}
else
{
if (left1 < right)
this.QuickSort(map, left1, right);
right = right1;
}
}
while (left < right);
}
原來是快速排序。
查看代碼,發現ThenBy和ThenByDescending基本一致,都是傳入IOrderedEnumerable<TSource>,返回其CreateOrderedEnumerable方法調用。
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, (IComparer<TKey>) null, false);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, comparer, false);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, (IComparer<TKey>) null, true);
}
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, comparer, true);
}
而在上面,我們已經發現了OrderBy與OrderByDescending都返回了OrderedEnumerable<TSource, TKey>,在其中找到CreateOrderedEnumerable方法。
IOrderedEnumerable<TElement> IOrderedEnumerable<TElement>.CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
OrderedEnumerable<TElement, TKey> orderedEnumerable = new OrderedEnumerable<TElement, TKey>(this.source, keySelector, comparer, descending);
orderedEnumerable.parent = this;
return (IOrderedEnumerable<TElement>) orderedEnumerable;
}
這說明正是在前面排序的基礎上進行再次排序。
C#集合--數組 - On the road.... - 博客園
比較排序算法 - 匠心十年 - 博客園
Introsort - Wikipedia, the free encyclopedia:
一並予以感謝