无法将 null 添加到可为 null 的列表
List<int?> listONullables = new List<int?>();
IList degenericed = listONullables;
// This works fine
listONullables.Add(null);
// Run time exception:
// "The value "" is not of type "System.Nullable`1[System.Int32]"
// and cannot be used in this generic collection. Parameter name: value"
degenericed.Add(null);
// Also does not work. Same exception
degenericed.Add((int?)null);
// Also does not work
// EDIT: I was mistaken, this does work
degenericed.Add((int?)1);
// Also does not work
// EDIT: I was mistaken, this does work
degenericed.Add(1);
请参阅上面代码中的注释。
我有点理解这样做的原因(当您放弃泛型时,运行时会在信息有限的情况下尽其所能)。我只是想知道是否有办法解决这个问题,即使它有点黑客。
当我尝试让函数的通用版本使用与非通用版本相同的私有实现时,问题就出现了,因此我可以在必要时解决它(有两个非常相似的实现),但显然如果我能弄清楚这一点会更好出去。
编辑:我上面的最后两个条目不会像我最初所说的那样失败。但前两个是这样的。我在上面的代码中添加了对此效果的注释。
Possible Duplicate:
Adding null to a List<bool?> cast as an IList throwing an exception.
List<int?> listONullables = new List<int?>();
IList degenericed = listONullables;
// This works fine
listONullables.Add(null);
// Run time exception:
// "The value "" is not of type "System.Nullable`1[System.Int32]"
// and cannot be used in this generic collection. Parameter name: value"
degenericed.Add(null);
// Also does not work. Same exception
degenericed.Add((int?)null);
// Also does not work
// EDIT: I was mistaken, this does work
degenericed.Add((int?)1);
// Also does not work
// EDIT: I was mistaken, this does work
degenericed.Add(1);
See the comments in the above code.
I sort of understand the reasons for this (when you cast away the generics the runtime does the best it can with limited information). I'm just wondering if there's a way around this, even if it's a bit of a hack.
The problem sprang up when I tried having the generic version of a function use the same private implementation as a non generic version, so I can work around it if necessary (have two very similar implementations), but obviously it's better if I can figure this out.
EDIT: The last two entries I have above do NOT fail like I originally said. But the first two do. I've added comments to that effect in the code above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
为了详细说明评论中的讨论,似乎在4.0中的
List.IList.Add
中,有:并且2.0有VerifyValueType,它只是检查IsCompatibleObject方法:
后者写在一种简约的时尚。
value
不是 T(因为 null 与Nullable.HasValue = false
不同)。另外,正如 @LBushkin 所指出的,typeof(T).IsValueType 将为Nullable
返回 true,因此右侧的计算结果也为 false。To elaborate on the discussion in the comments, it seems that in
List<T>.IList.Add
in 4.0, there is:And 2.0 has VerifyValueType which simply checks the IsCompatibleObject method:
The latter is written in a simplistic fashion.
value
is not T (because null is not the same asNullable<int>.HasValue = false
). Also, as @LBushkin notes, typeof(T).IsValueType will return true forNullable<int>
and so the right-hand-side also evaluates to false.这是 3.5 框架中的一个错误(可能也是早期版本)。这个答案的其余部分与 .NET 3.5 相关,尽管注释表明该错误已在框架的版本 4 中修复...
当您将值类型传递给
IList.Add
方法时由于IList
接口是非泛型的,它将被装箱为对象
。此规则的一个例外是null
可空类型,它们会转换(未装箱)为普通null
。List
类上的IList.Add
方法检查您尝试添加的类型实际上是T
,但兼容性检查不会考虑null
可空类型:当您传递
null
时,兼容性检查知道您的列表是List
并知道int?
是值类型,但是 - 这是错误 - 抛出错误,因为它也“知道”值类型不能可能是null
,因此您传递的null
不可能是int?
。This is a bug in the 3.5 framework (and probably earlier versions too). The rest of this answer relates to .NET 3.5, although the comments suggest that the bug has been fixed in version 4 of the framework...
When you pass a value-type to the
IList.Add
method it will be boxed as anobject
due to theIList
interface being non-generic. The one exception to this rule arenull
nullable types which are converted (not boxed) to plainnull
.The
IList.Add
method on theList<T>
class checks that the type you're trying to add is actually aT
, but the compatibility check doesn't takenull
nullable types into account:When you pass
null
, the compatibility check knows that your list is aList<int?>
and knows thatint?
is a value-type, but -- here's the bug -- throws an error because it also "knows" that value-types cannot possibly benull
, ergo thenull
that you passed cannot possibly be anint?
.这在 .NET 4.0 中有效,引入了协变和逆变。
由于您不在 4.0 中(显然是由于运行时错误),您可以通过传递 default(int) 来获取 null 值来解决它
更新:不要听我的 default(int) = 0 NOT null。我很迟钝:(
这适用于 null:add 调用对我来说工作正常吗?
This works in .NET 4.0 with the introduction of Covariance and contravariance.
Since you are not in 4.0 (obviously due to the runtime error) you can work around it by passing default(int) to get a null value
UPDATE: Don't listen to me default(int) = 0 NOT null. I am retarded :(
This works for null:The add call works correctly for me though?
尝试更改行:
通过以下方式:
try to change the line:
by this: