通过Activator创建一个可空对象.CreateInstance返回null



我正在创建一个将小脚本转换为dll的系统。当我尝试使用可空值类并将其作为参数的默认值时,我遇到了一个问题。问题是我需要在编译器中创建一个user selected nullable的实例,并将其设置为常量。

不幸的是,每当我使用Activator.CreateInstance(NullableType)(其中NullableType是从用户输入创建的类型)时,我得到null作为返回值。例如,简单地执行:

object Test = Activator.CreateInstance(typeof(Nullable<int>));
Console.WriteLine(Test == null);

返回true。这种只发生在中。c#中创建的结构体,即使是泛型结构体,也可以创建得很好。哎呀,如果我复制&从DotNetReflector粘贴nullable(并删除TypeDependencyAttribute, TargetPatchingOptOutAttribute,和ThrowHelper调用,因为我没有访问这些),它显示上面的False。

怎么回事?是否有任何其他可能的方法来创建一个空当我不知道的通用参数,直到运行时?

From this MSDN blog:

活化剂。永远不能期望CreateInstance返回null之前;使用此DCR,在创建实例时将返回nulltype可为空但不提供非空T值。例如,Activator.CreateInstance(typeof(Int32?))返回null.

这个问题与Nullable<T>的变量如何装箱有关,正如博客文章所解释的。

问题是在ParameterBuilder.SetConstant,而不是Activator.CreateInstanceSetConstant是定义可选参数默认值的函数,需要提供一个具体的值作为常量。对于ref类,null是一个有效的具体值,但是对于创建Nullable<>之前的值类,null不是一个有效值。例如,如何将null拆成int ?因此,SetConstant检查值类型,看看作为常量传入的具体值是否为null,并抛出ArgumentException,作为一个更具描述性的错误,而不是将null拆箱到值类中所得到的NullReferenceException

Nullable<>的情况下,null现在是值类的有效具体值。Nullable<>本身是一个值类,就像Activator.CreateInstance一样,将null拆箱到Nullable<int>中是有意义的。这就是SetConstant有一个bug的地方:它没有考虑到这一点,并抛出了一个"描述性"错误,而实际上并不是一个错误。代替微软的错误修复,任何使用空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
});

我已经向微软报告了这个bug。他们回应说,这个问题不会在。net 3.5中修复,但它被添加到内部错误数据库中。

更新:

该错误已在。net 4.0中修复。ParameterBuilder.SetConstant现在有一个constant == null条件的分支,检查值类型是否是从Nullable<>派生的泛型,如果不是,则抛出异常。

相关内容

  • 没有找到相关文章

最新更新