22

Im trying to use the following code:

private Nullable<List<IpAddressRange>> ipAddressRangeToBind;

But I am getting the following warning:

The type List must be a non-nullable value type in order to use it as a parameter 'T' in the generic type or method 'System.Nullable'.

Exitos
  • 29,230
  • 38
  • 123
  • 178

4 Answers4

53

List<T> is already a reference type (for any kind of T) - you can only declare Nullable<T> where T is a non-nullable value type (it's declared as Nullable<T> where T : struct).

But that's okay, because if you just declare:

private List<IpAddressRange> ipAddressRangeToBind;

then you can still have

ipAddressRangeToBind = null;

because reference types are always nullable.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
11

List<IpAddressRange> is a reference type - it is already nullable - in fact it will be initialized to null by that declaration.

Cade Roux
  • 88,164
  • 40
  • 182
  • 265
7

You can just use it as is:

List<IpAddressRange> ipAddressRangeToBind = null;  

List is already nullable.

Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94
  • true true, why cant I do it though out of interest...? – Exitos Sep 14 '11 at 15:24
  • 2
    I guess because as The Jon Skeet explained, the of the constraint `Nullable where T : struct` and `IpAddressRange` is not a `struct`. Why the constraint you ask? That's a different question :) – Miserable Variable Sep 14 '11 at 15:26
  • @Pete2k: I added an answer as to why don't the constraint exists. It wasn't the first answer, so I don't want to claim credit for the answer, but it was too long to just put in a comment... – James Michael Hare Sep 14 '11 at 16:00
4

Reference types cannot be wrapped in Nullable<T> due to a where T : struct constraint on the generic.

The reasons for this constraint are:

  1. Reference types are already nullable by definition, and
  2. Nullable is not very space efficient, but more a "logical" nullability.

Nullable<T> has a bool property HasValue and a type T property Value which contains the actual value-type value.

Even if HasValue == false (that is, if the nullable wrapped variable is set to null), you STILL consume the space for the value type as if it was there.

It's logically nullable to allow you to specify optional behavior, but it doesn't save any space. This is very similar to how boost::optional works in C++.

James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
  • I see now what the Where clause is now! – Exitos Sep 16 '11 at 09:09
  • A lot of annoyances with `Nullable` stem from a desire to have it pretend that an empty instance is `null`. An unfortunate decision, IMHO, since it prevents methods like `TryGetValue`, which may or may not have a `T` to return, from simply returning a `TValue?` without having to worry about the type of `TValue` (if the `HasValue` of the returned item is false, the key does not exist; if `HasValue` is true, the key exists even if the stored `Value` happens to be `null`). On the other hand, while nullable types should logically be covariant with their type parameter... – supercat Oct 30 '12 at 18:36
  • ...(since any `Animal?` should be able to hold the contents of any `Cat?`), making covariance work while having a cast from `Animal?` or `Animal??` to `Object` preserve the degree of nullability, would require that conversion from a nullable type to `Object` not use normal boxing. Under normal boxing rules, boxed value types are *always* mutable (even if the underlying value type is supposedly "immutable"). Too bad, since such a design increases the difficulty of making things like a "readable dictionary" interface covariant with regard to types of values stored therein. – supercat Oct 30 '12 at 18:47