简体   繁体   中英

Adding null to a List<bool?> cast as an IList throwing an exception

Using .NET 3.5 and C# 3.0,

IList list = new List<bool?>();
list.Add(null);

This throws an ArgumentException, which just feels wrong.

List<bool?> list = new List<bool?>();
list.Add(null);

Works perfectly.

Is this a bug in Microsoft's code, then?

An example of how to produce this kind of error in a real-life situation:

new JavaScriptSerializer().Deserialize<List<bool?>>("[true, false, null]");

Yes, it is. See http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/abc99fb5-e218-4efa-8969-3d96f6021cee/ for other reports. Basically when you access the List<bool?> through its weak-typed IList implementation, it does some type checking before trying to add the item to the internal storage -- and it gets this type checking wrong for nullable types.

It's "By Design" and explicitly so. The reason why is that List<T> has an explicit implementation of IList . It filters values passed to the various methods to do a bit of null checking. The logic essentially is the following

if (default(T) != null && value == null) { throw ... }

In this case the default of a value type (and nullable is a value type) is not null hence it's not allowed.

Ha! That's a funny one. I believe it has to do with the idea that the nullable bool is, strictly speaking, implemented as a struct and IList expects an object, and maybe it's expecting to box a bool or something. Jon Skeet where are you? We need you! (taps ruby slippers 3 times)

When you call the Add method on the IList with a null value, it's a null reference that you are passing to the method, not a nullable value. The null reference can't be converted into a nullable value.

The Add method expects something that contains a bool or a bool? . As you can't box a null value, you can't create an object that is possible to use to add a null value to the IList .

If you use the generic interface IList<bool?> instead, there is no problem adding the value:

IList<bool?> list = new List<bool?>();
list.Add(null);

As it has been pointed out, there is a bug in the implementation of IList.Add(object item) method in List <T> class in .NET 3.5 (and maybe before). The thing is, that IList.Add(object item) method tries to verify that the object, we're trying to add is an object compatible with the List <T> generic type argument, which fails when we're trying to add null to the list of nullable value types.

My workaround involves reflection by getting and invoking Add(T item) method from List object.

IList list = new List<bool?>();
MethodInfo addMethod = list.GetType().GetMethod("Add");
addMethod.Invoke(list, new object[] { null });

You're mixing the Generic List<T> with the non-generic IList . List<T> inherits from IList<T> and not from IList .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM