[英]Creating a nullable object via Activator.CreateInstance returns null
我正在創建一個將小腳本變成dll的系統。 當我嘗試獲取可為空的值類並將其設置為參數的默認值時,我遇到了問題。 問題是我需要在編譯器中創建一個用戶選擇為nullable的實例,並將其設置為常量。
不幸的是,每當我使用Activator.CreateInstance(NullableType)
(其中NullableType是來自用戶輸入的創建類型)時,我得到null
作為返回值。 例如,只需執行:
object Test = Activator.CreateInstance(typeof(Nullable<int>));
Console.WriteLine(Test == null);
返回true。 這僅與Nullables發生。 在C#中創建的結構,甚至是通用結構,都可以很好地創建。 哎呀,如果我從DotNetReflector復制並粘貼nullable(並刪除TypeDependencyAttribute,TargetPatchingOptOutAttribute和ThrowHelper調用,因為我沒有訪問權限),它會在上面顯示False。
到底是怎么回事? 當我在運行時之前不知道通用參數時,還有其他可能的方法來創建可空嗎?
來自這篇MSDN博客 :
永遠不會期望Activator.CreateInstance返回null; 使用此DCR,它將在創建Nullable類型的實例時返回null,但不提供非空T值。 例如,Activator.CreateInstance(typeof(Int32?))返回null。
問題與如何將Nullable<T>
變量裝箱,如博客文章所解釋的那樣。
問題出在ParameterBuilder.SetConstant
,而不是Activator.CreateInstance
。 SetConstant
是用於定義可選參數的默認值的函數,並且需要提供具體值作為常量。 對於ref類, null
是一個有效的具體值,但對於創建Nullable<>
之前的值類, null
不是有效值。 例如,如何將unbox null
轉換為int
? 因此, SetConstant
檢查了值類型,以查看作為常量傳入的具體值是否為null
並將ArgumentException
作為比NullReferenceException
更具描述性的錯誤拋出,以便將null拆分為值類。
在Nullable<>
的情況下, null
現在是值類的有效具體值。 Nullable<>
本身是一個值類,如Activator.CreateInstance
,並且取消裝入null
到Nullable<int>
具有意義。 這就是SetConstant
有一個錯誤的地方:它沒有考慮到這一點,並且對於實際上不是錯誤的內容拋出了“描述性”錯誤。 代替Microsoft的錯誤修復,任何使用null Nullable<>
SetConstant
調用都必須實現由不正確的條件保護的行為。 這意味着使用反射挖掘ParameterBuilder
的私有方法和字段。 下面是我做處理只是這種情況下的代碼。 標准SetConstant
函數應該在不顯示錯誤的情況下使用。
//ModuleBuilder module : a parameter passed into the containing function, the module which is being built (which contains the method that has the optional parameter we are setting the constant for)
//ParameterBuilder optParam : A parameter passed into the containing function, the parameter that is being built which is to have the null default value.
MethodInfo method = typeof(TypeBuilder).GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.Where(m => m.Name == "SetConstantValue" && m.GetParameters().Length > 0 && m.GetParameters()[0].ParameterType.Name == "RuntimeModule")
.Single();
var RuntimeHandle = typeof(ModuleBuilder).GetMethod("GetNativeHandle", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(null, new object[]
{
RuntimeHandle.Invoke(module, new object[]{}),
optParam.GetToken().Token,
0x12,
null
});
我已經向微軟報告了這個錯誤。 他們回答說它不會在.NET 3.5中修復,但它被添加到內部bug數據庫中。
更新:
該錯誤已在.NET 4.0中修復。 ParameterBuilder.SetConstant
現在有一個constant == null
條件的分支,它檢查值類型是否是從Nullable<>
派生的泛型,如果不是則僅拋出異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.