Я вижу следующие два способа создания массива int в C #:
Через API в
System.Array
абстрактном классе:var arrayInstance = Array.CreateInstance(typeof(int), 4);
Через различные синтаксис инициализации массива:
var arrayInstanceWithSyntax = new int[4];
Вышеупомянутые два способа абсолютно идентичны? Преобразует ли компилятор второй синтаксис в первый синтаксис во время самой компиляции (присутствует в MSIL), или существует некоторое волшебство JIT на уровне CLR, которое происходит во время выполнения, или нет никакого преобразования между двумя синтаксисами кода?
2 ответа
Они определенно создают одно и то же значение - в отличие от того, что вы вызываете, например, Array.CreateInstance
и создаете массив с ненулевой нижней границей.
Тем не менее, они не одинаковы с точки зрения IL - первый - просто вызов метода, второй использует инструкцию newarr
IL.
Здесь не должно быть никакой «магии JIT» - есть только два пути для создания одинаковых значений.
Тип вашей первой переменной время компиляции просто Array
- вам нужно привести его к int[]
, чтобы два куска кода действительно имели одинаковый результат ,
Я бы всегда использовал синтаксис создания массива "C # native" там, где это возможно - используйте Array.CreateInstance
только тогда, когда у вас есть элемент Type
по какой-то причине (вместо того, чтобы знать во время компиляции, даже через параметр универсального типа) ... или если вы пытаетесь создать массив, который может иметь ненулевую нижнюю границу.
Краткий ответ: Нет, они производят разные IL. Вы можете увидеть это сами по Попробуйте 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, реализованную в другом месте, за пределами управляемого кода.
new int [4];
Это встроено в C #, поэтому компилятор C # позаботится об этом и создаст массив. Как? Я не уверена.
Надеюсь, это немного прояснит ситуацию.
Похожие вопросы
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.