可能重复:
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);
请参阅上述代码中的注释。
我有点理解这个的原因(当你丢弃泛型时,运行时会尽可能地利用有限的信息)。我只是想知道是否有办法绕过这个,即使它有点像黑客。
当我尝试使用通用版本的函数使用相同的私有实现作为非泛型版本时出现问题,所以我可以在必要时解决它(有两个非常类似的实现),但显然如果我更好可以搞清楚这一点。
编辑:我上面的最后两个条目并没有像我最初说的那样失败。但前两个呢。我在上面的代码中添加了对该效果的评论。
答案 0 :(得分:5)
为了详细说明评论中的讨论,似乎在4.0中的List<T>.IList.Add
中有:
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
try
{
this.Add((T) item);
}
catch (InvalidCastException)
{
ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
}
2.0有VerifyValueType,它只检查IsCompatibleObject方法:
VerifyValueType(item);
...
private static bool IsCompatibleObject(object value) {
if( (value is T) || ( value == null && !typeof(T).IsValueType) ) {
return true;
}
return false;
}
后者以简单的方式编写。 value
不是T(因为null与Nullable<int>.HasValue = false
不同)。另外,正如@LBushkin所说,typeof(T).IsValueType将为Nullable<int>
返回true,因此右侧也会评估为false。
答案 1 :(得分:2)
这是3.5框架中的错误(也可能是早期版本)。这个答案的其余部分与.NET 3.5有关,虽然评论表明该错误已在框架的第4版中得到修复......
当您将值类型传递给IList.Add
方法时,由于object
接口是非泛型的,因此它将被设置为IList
。此规则的一个例外是null
可空类型,它们被转换(不加框)到普通null
。
IList.Add
类上的List<T>
方法会检查您尝试添加的类型实际上是T
,,但兼容性检查不会null
1}}可以考虑的可空类型:
当您通过null
时,兼容性检查知道您的列表是List<int?>
,并且知道int?
是值类型,但是 - 这是错误 - 抛出一个错误,因为它也“知道”值类型不可能是null
,因此您传递的null
不可能是int?
。
答案 2 :(得分:1)
这适用于.NET 4.0,引入了协方差和逆变。
由于您不在4.0中(显然是由于运行时错误),您可以通过传递default(int)来获取空值来解决它
更新:不要听我默认(int)= 0 NOT null。我很迟钝:(
这适用于null:
degenericed.Add(default(int));
击> <击> 撞击>
虽然add call对我有用吗?
degenericed.Add(1);
答案 3 :(得分:0)
尝试更改该行:
IList degenericed = listONullables;
由此:
IList<int?> degenericed = listONullables;