我可以看到以下两种在C#中实例化int数组的方法:
通过System.Array
抽象类中的API:
var arrayInstance = Array.CreateInstance(typeof(int), 4);
通过各种数组初始化语法:
var arrayInstanceWithSyntax = new int[4];
上述两种方式完全相同吗?编译器是否在编译时将第二种语法转换为第一种语法(存在于MSIL中),或者在CLR级别存在一些JIT魔术,它在运行时发生,或者两种代码语法之间根本没有转换?
答案 0 :(得分:5)
它们肯定会创建相同类型的值 - 例如,与调用Array.CreateInstance
并创建一个非零下限的数组不同。
然而,它们在IL方面并不相同 - 第一个只是方法调用,第二个使用newarr
IL指令。
不需要任何类型的" JIT魔法"这里 - 只有两条路径可以创建相同类型的值。
您的第一个变量的编译时类型只是Array
- 您必须将其转换为int[]
,以便将两个代码转换为Array.CreateInstance
真的有相同的结果。
我会一直使用" C#native"尽可能使用数组创建语法 - 当出于某种原因(而不是在编译时知道,甚至通过泛型类型参数)时,仅使用Type
...或者如果你'重新尝试创建一个可能具有非零下限的数组。
答案 1 :(得分:2)
简答:不会产生不同的IL。您可以在Try Roslyn上自行查看。
<强> Array.CreateInstance 强>
I/System.out: client
I/BluetoothSocket.cpp: Setting Master socket option
I/System.out: connecting
W/System.err: java.io.IOException: Unable to start Service Discovery
W/System.err: at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:494)
W/System.err: at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:252)
W/System.err: at ml.minary.example.MainActivity.onConnectAsClientClick(MainActivity.java:61)
W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err: at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err: at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
W/System.err: at android.view.View.performClick(View.java:4336)
W/System.err: at android.view.View$PerformClick.run(View.java:17587)
W/System.err: at android.os.Handler.handleCallback(Handler.java:725)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err: at android.os.Looper.loop(Looper.java:137)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5230)
W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err: at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
W/System.err: at dalvik.system.NativeStart.main(Native Method)
方法是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);
}
在哪里实施?它在 arraynative.cpp 类中实现。这是代码:
[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);
正如您所看到的,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);
}
使用在托管代码之外的其他地方实现的外部DLL。
new int [4];
这是C#的原生代码,因此C#编译器会处理它并创建数组。怎么样?我不确定。
我希望能澄清一些事情。