簡短的回答:不,他們產生不同的IL。你可以在Try Roslyn上看到這個。
Array.CreateInstance
的CreateInstance
方法是在Array
類工廠方法,它返回一個類型的Array
。這裏是該方法的源代碼:
[System.Security.SecuritySafeCritical] // auto-generated
public unsafe static Array CreateInstance(Type elementType, int length)
{
if ((object)elementType == null)
throw new ArgumentNullException("elementType");
if (length < 0)
throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.Ensures(Contract.Result<Array>() != null);
Contract.Ensures(Contract.Result<Array>().Length == length);
Contract.Ensures(Contract.Result<Array>().Rank == 1);
Contract.EndContractBlock();
RuntimeType t = elementType.UnderlyingSystemType as RuntimeType;
if (t == null)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "elementType");
return InternalCreate((void*)t.TypeHandle.Value, 1, &length, null);
}
請注意上述方法中的最後一行代碼。該方法的主體只是一個分號,它是在其他地方實施的一種方法。這裏是身體:
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private unsafe static extern Array InternalCreate(void* elementType, int rank, int* pLengths, int* pLowerBounds);
在哪裏實施?它在arraynative.cpp類中實現。下面是代碼:
FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pLowerBounds) {
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(rank > 0);
PRECONDITION(CheckPointer(pLengths));
PRECONDITION(CheckPointer(pLowerBounds, NULL_OK));
}
CONTRACTL_END;
OBJECTREF pRet = NULL;
TypeHandle elementType = TypeHandle::FromPtr(elementTypeHandle);
_ASSERTE(!elementType.IsNull());
// pLengths and pLowerBounds are pinned buffers. No need to protect them.
HELPER_METHOD_FRAME_BEGIN_RET_0();
CheckElementType(elementType);
CorElementType CorType = elementType.GetSignatureCorElementType();
CorElementType kind = ELEMENT_TYPE_ARRAY;
// Is it ELEMENT_TYPE_SZARRAY array?
if (rank == 1 && (pLowerBounds == NULL || pLowerBounds[0] == 0)
# ifdef FEATURE_64BIT_ALIGNMENT
// On platforms where 64-bit types require 64-bit alignment and don't obtain it naturally force us
// through the slow path where this will be handled.
&& (CorType != ELEMENT_TYPE_I8)
&& (CorType != ELEMENT_TYPE_U8)
&& (CorType != ELEMENT_TYPE_R8)
#endif
)
{
// Shortcut for common cases
if (CorTypeInfo::IsPrimitiveType(CorType))
{
pRet = AllocatePrimitiveArray(CorType, pLengths[0]);
goto Done;
}
else
if (CorTypeInfo::IsObjRef(CorType))
{
pRet = AllocateObjectArray(pLengths[0], elementType);
goto Done;
}
kind = ELEMENT_TYPE_SZARRAY;
pLowerBounds = NULL;
}
{
// Find the Array class...
TypeHandle typeHnd = ClassLoader::LoadArrayTypeThrowing(elementType, kind, rank);
DWORD boundsSize = 0;
INT32* bounds;
if (pLowerBounds != NULL)
{
if (!ClrSafeInt <DWORD>::multiply(rank, 2, boundsSize))
COMPlusThrowOM();
DWORD dwAllocaSize = 0;
if (!ClrSafeInt <DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
COMPlusThrowOM();
bounds = (INT32*)_alloca(dwAllocaSize);
for (int i = 0; i < rank; i++)
{
bounds[2 * i] = pLowerBounds[i];
bounds[2 * i + 1] = pLengths[i];
}
}
else
{
boundsSize = rank;
DWORD dwAllocaSize = 0;
if (!ClrSafeInt <DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
COMPlusThrowOM();
bounds = (INT32*)_alloca(dwAllocaSize);
// We need to create a private copy of pLengths to avoid holes caused
// by caller mutating the array
for (int i = 0; i < rank; i++)
bounds[i] = pLengths[i];
}
pRet = AllocateArrayEx(typeHnd, bounds, boundsSize);
}
Done:;
HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(pRet);
}
正如你可以看到Array.CreateInstance
使用其它地方執行外部DLL,託管代碼之外。
新INT [4];
這是C#原生的,所以C#編譯器會照顧它並創建數組。怎麼樣?我不確定。
我希望澄清一點事情。
是的,它們依賴於CLR中的相同管道,而不是編譯器參與。 Type.MakeArrayType()重載也更普遍地暴露出來。第二種風味嚴重微觀優化。 –
從早上起,我一直在使用googling來獲取一些內部函數,看看編譯器如何將'new int [4]'轉換爲數組類型實例,因爲'System.Array'是.Net中的抽象類,'int []'不是這些東西可以直接轉換成.Net FCL中的類型。你能幫我一些鏈接,這可以幫助我更多地瞭解這一點。 – RBT
數組類型非常不尋常,CLR動態創建它們。您必須閱讀CLR源代碼才能瞭解它的底部。這可以讓你忙一段時間,需要C++技能,但它可以從CoreCLR github項目中獲得。搜索「AllocateArrayEx」和「FastAllocatePrimitiveArray」以查找最相關的代碼。 –