我正在嘗試構建一個動態屬性訪問器。想要的東西就像接近調用實際屬性一樣快。不想去反射路線,因爲它非常緩慢。所以我選擇使用DynamicAssembly並使用ILGenerator注入IL。下面是似乎工作的ILGenerator相關的代碼ILGenerator。這個代碼有什麼問題
Label nulllabel = getIL.DefineLabel();
Label returnlabel = getIL.DefineLabel();
//_type = targetGetMethod.ReturnType;
if (methods.Count > 0)
{
getIL.DeclareLocal(typeof(object));
getIL.DeclareLocal(typeof(bool));
getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
//(target object)
//Cast to the source type
getIL.Emit(OpCodes.Castclass, this.mTargetType);
//Get the property value
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
getIL.Emit(OpCodes.Stloc_0); //Store it
getIL.Emit(OpCodes.Br_S,returnlabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Stloc_0);
getIL.MarkLabel(returnlabel);
getIL.Emit(OpCodes.Ldloc_0);
}
else
{
getIL.ThrowException(typeof(MissingMethodException));
}
getIL.Emit(OpCodes.Ret);
因此,上面得到第一個參數,它是包含該屬性的對象。方法集合包含嵌套屬性(如果有的話)。對於每個屬性,我使用EmitCall將值放在堆棧上,然後我嘗試將其封裝。這像一個魅力。
唯一的問題是,如果您有像Order.Instrument.Symbol.Name這樣的屬性並假定Instrument對象爲null。然後代碼會拋出一個空對象異常。
所以這個我做什麼,我介紹了一個空檢查
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
getIL.Emit(OpCodes.Stloc_0);
getIL.Emit(OpCodes.Ldloc_0);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Ceq);
getIL.Emit(OpCodes.Stloc_1);
getIL.Emit(OpCodes.Ldloc_1);
getIL.Emit(OpCodes.Brtrue_S, nulllabel);
getIL.Emit(OpCodes.Ldloc_0);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
下面這段代碼符說,對象/內存損壞等,所以究竟是什麼不對的代碼。我在這裏錯過了什麼。
在此先感謝。