虽然我正在研究一些微观性能技术,但我在array.cs file中在.net框架中遇到了对二进制搜索函数的外部引用。
private static extern bool TrySZBinarySearch(Array sourceArray, int sourceIndex, int count, Object value, out int retVal);
我在哪里可以找到此功能的文档?或者更好,它是如何实现的? 为什么.net中有这么多的SZ?
private static extern bool TrySZIndexOf(Array sourceArray, int sourceIndex, int count, Object value, out int retVal);
private static extern bool TrySZLastIndexOf(Array sourceArray, int sourceIndex, int count, Object value, out int retVal);
sealed class SZArrayHelper { ... }
等
答案 0 :(得分:5)
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static extern bool TrySZBinarySearch(Array sourceArray,
int sourceIndex, int count, Object value, out int retVal);
这是从参考源检索到的声明。其中包含.NET框架的绝大部分源代码。您可以下载it here。
[MethodImpl(MethodImplOptions.InternalCall)]赋予的方法是用C ++编写的,包含在CLR中。 CLR的源代码也可以从SSCLI20获得,SSCLI20是CLR的共享源版本,旨在帮助将.NET移植到其他操作系统。它有点过时了,因为它是在.NET 2.0时间框架发布的,但许多主辅助函数仍然是准确的。您可以下载it here。
你会在clr / src / vm / ecall.cpp中找到TrySZBinarySearch,这是寻找InternalCall方法的第一个地方。您将看到它映射到ArrayHelper :: TrySZBinarySearch()C ++方法,您将在clr / src / vm / comarrayhelper.cpp中找到它
没有什么特别有趣的,只是一个专门用于各种简单值类型的纯二进制搜索算法。你可以在this answer中找到它用C ++而不是C#编写的原因。
SZ是单维零基础的缩写,是从C#array []声明中获得的那种数组。在C#中更好地称为“向量”。由于它是如此常用,因此经过微量优化。
更新:今天使用github提供的CoreCLR源代码更容易看到,函数is here。
答案 1 :(得分:1)
[MethodImplAttribute(MethodImplOptions.InternalCall)]
方法声明上的...表示这是作为本机方法(即通常为C ++ /汇编)实现的,而不是在.NET中实现(例如C#)。你会在SSCLI的clr \ src \ _vm \ comarrayhelpers.cpp中找到实现(留下深入调查作为读者的练习 - 汉斯帕斯特已经解释了你会发现什么比我能找到的更好):
FCIMPL5(FC_BOOL_RET, ArrayHelper::TrySZBinarySearch, ArrayBase * array, UINT32 index, UINT32 count, Object * value, INT32 * retVal)
WRAPPER_CONTRACT;
STATIC_CONTRACT_SO_TOLERANT;
VALIDATEOBJECTREF(array);
_ASSERTE(array != NULL);
if (array->GetRank() != 1 || array->GetLowerBoundsPtr()[0] != 0)
FC_RETURN_BOOL(FALSE);
_ASSERTE(retVal != NULL);
_ASSERTE(index <= array->GetNumComponents());
_ASSERTE(count <= array->GetNumComponents());
_ASSERTE(array->GetNumComponents() >= index + count);
*retVal = 0xdeadbeef; // Initialize the return value.
// value can be NULL, but of course, will not be in primitive arrays.
TypeHandle arrayTH = array->GetArrayElementTypeHandle();
const CorElementType arrayElType = arrayTH.GetVerifierCorElementType();
if (!CorTypeInfo::IsPrimitiveType(arrayElType))
FC_RETURN_BOOL(FALSE);
// Handle special case of looking for a NULL object in a primitive array.
if (value == NULL) {
*retVal = -1;
FC_RETURN_BOOL(TRUE);
}
TypeHandle valueTH = value->GetTypeHandle();
if (arrayTH != valueTH)
FC_RETURN_BOOL(FALSE);
switch(arrayElType) {
case ELEMENT_TYPE_I1:
*retVal = ArrayHelpers<I1>::BinarySearchBitwiseEquals((I1*) array->GetDataPtr(), index, count, *(I1*)value->UnBox());
break;
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_BOOLEAN:
*retVal = ArrayHelpers<U1>::BinarySearchBitwiseEquals((U1*) array->GetDataPtr(), index, count, *(U1*)value->UnBox());
break;
case ELEMENT_TYPE_I2:
*retVal = ArrayHelpers<I2>::BinarySearchBitwiseEquals((I2*) array->GetDataPtr(), index, count, *(I2*)value->UnBox());
break;
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_CHAR:
*retVal = ArrayHelpers<U2>::BinarySearchBitwiseEquals((U2*) array->GetDataPtr(), index, count, *(U2*)value->UnBox());
break;
case ELEMENT_TYPE_I4:
*retVal = ArrayHelpers<I4>::BinarySearchBitwiseEquals((I4*) array->GetDataPtr(), index, count, *(I4*)value->UnBox());
break;
case ELEMENT_TYPE_U4:
*retVal = ArrayHelpers<U4>::BinarySearchBitwiseEquals((U4*) array->GetDataPtr(), index, count, *(U4*)value->UnBox());
break;
case ELEMENT_TYPE_R4:
*retVal = ArrayHelpers<R4>::BinarySearchBitwiseEquals((R4*) array->GetDataPtr(), index, count, *(R4*)value->UnBox());
break;
case ELEMENT_TYPE_I8:
*retVal = ArrayHelpers<I8>::BinarySearchBitwiseEquals((I8*) array->GetDataPtr(), index, count, *(I8*)value->UnBox());
break;
case ELEMENT_TYPE_U8:
*retVal = ArrayHelpers<U8>::BinarySearchBitwiseEquals((U8*) array->GetDataPtr(), index, count, *(U8*)value->UnBox());
break;
case ELEMENT_TYPE_R8:
*retVal = ArrayHelpers<R8>::BinarySearchBitwiseEquals((R8*) array->GetDataPtr(), index, count, *(R8*)value->UnBox());
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::TrySZBinarySearch");
FC_RETURN_BOOL(FALSE);
}
FC_RETURN_BOOL(TRUE);
FCIMPLEND
各种方法名称中的SZ
指的是“ S 单个维度, Z 基于ero”的数组。这就是你将得到的东西,例如:
int[] myArray;
或
MyObject[] myArray;
...与.NET中的另一种更通用的数组相反,它可以是多维的:
int[,] myArray;
...或者可能有不同于0的下限:
// Creates a single-dimensional array of size 10 with a lower bound of 5
// - as far as I recall C# doesn't have any dedicated declaration for this.
// It's mainly there to support other languages:
Array myArray = Array.CreateInstance(
typeof(int),
new int[] { 10 },
new int[] { 5 }
);
SZ阵列性能更高,更优化,因此通常更受欢迎。这就是为什么你会在CLR代码中看到这么多对它们的引用(因此在上面的代码中早期检查排名和下限的原因)。