簡體   English   中英

通過Activator.CreateInstance創建可為空的對象返回null

[英]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 ,並且取消裝入nullNullable<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM