【问题标题】:Activator.CreateInstance creates value of type T instead of Nullable<T>Activator.CreateInstance 创建类型为 T 而不是 Nullable<T> 的值
【发布时间】:2015-08-12 14:41:51
【问题描述】:

看下面的示例代码

var genericNullableType = typeof(Nullable<>);
var nullableType = genericNullableType.MakeGenericType(typeof(bool));
var returnValue = Activator.CreateInstance(nullableType, (object)false);

由于某种原因,returnValue 变量的类型将是 bool 而不是 bool?。为什么会这样?如何避免?

UPD:这是我的 VS 的屏幕截图

【问题讨论】:

  • @petelids 我使用的是 VS 2013 Premium 和 .NET Framework 4.5,构建配置是 Debug。你使用相同的配置吗?
  • 这不是 Activator 独有的。 Console.WriteLine((new Nullable&lt;bool&gt;(false).GetType().FullName)); 也只是吐出普通的布尔值。
  • 没有办法获得一个可空的盒装。运行时对可为空的装箱进行特殊处理,并将始终将其解包为基础类型的装箱值或空引用。也就是说它应该可以转换为bool?,所以我不确定你在找什么。
  • 这是 Brad Wilson Creating Nullable&lt;T&gt; When You Don't Know T 的相关博文

标签: c# activator


【解决方案1】:

在这种特殊情况下,您使用的是CreateInstance 的重载,它返回objectNullable&lt;T&gt;struct 因此要表示为 object 它需要被装箱。然而,Nullable&lt;T&gt; 实际上并不能被 CLR 的规则装箱。而是使用基础值或null。这就是为什么你在这里得到一个原始的bool 而不是bool?

文档:https://msdn.microsoft.com/en-us/library/ms228597.aspx

编辑

在确定值的类型是否可以为空时似乎有些混乱。特别是有人指出以下打印System.Boolean而不是System.Nullable``1[System.Boolean]

var x = (bool?)true;
Console.WriteLine(x.GetType());

此代码也成为拳击的牺牲品。对GetType 的调用具有隐式装箱操作,因为它是object 上的虚方法调用,而不是Nullable&lt;T&gt; 上的方法:

IL_0009: ldloc.0
IL_000a: box valuetype [mscorlib]System.Nullable`1<bool>
IL_000f: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_0014: call void [mscorlib]System.Console::WriteLine(object)

打印出var 值的实际类型的最安全方法是使用泛型执行以下技巧:

static void PrintType<T>(T value)
{
    Console.WriteLine(typeof(T));
}

PrintType(x);  // Prints System.Nullable`1[System.Boolean]

【讨论】:

  • 即使使用了另一个重载的 CreateInstance,GetType 仍然会在内部装箱,因为它是非虚拟的,因此您永远不会看到 GetType 之外的 Nullable&lt;T&gt;,对吗?
  • @mikez 正确。对GetType() 的调用会生成一个隐式.box il 操作码,以防止它吐出可空类型。要获得要打印的真实类型,您需要使用泛型。将在几秒钟内证明这一点。
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2015-04-24
  • 2012-02-25
  • 2021-07-19
相关资源
最近更新 更多