5

If have the following method:

static void DoSomethingWithTwoNullables(Nullable<int> a, Nullable<int> b)
{
    Console.WriteLine("Param a is Nullable<int>: " + (a is Nullable<int>));
    Console.WriteLine("Param a is int          : " + (a is int));
    Console.WriteLine("Param b is Nullable<int>: " + (b is Nullable<int>));
    Console.WriteLine("Param b is int          : " + (b is int));
}

When i call this method with null as a parameter, the type check returns false for this parameter. For example this code

DoSomethingWithTwoNullables(5, new Nullable<int>());

results in this output:

Param a is Nullable<int>: True
Param a is int          : True
Param b is Nullable<int>: False
Param b is int          : False

Is there any way to preserve the type information when using a Nullable and passing null? I know that checking the type in this example is useless, but it illustrates the problem. In my project, I pass the parameters to another method that takes a params object[] array and tries to identify the type of the objects. This method needs to do different things for Nullable<int> and Nullable<long>.

bernd_rausch
  • 335
  • 2
  • 9

8 Answers8

5

Going straight to the underlying problem, no, you can't do this. A null Nullable<int> has exactly the same boxed representation as a null Nullable<long>, or indeed a 'normal' null. There is no way to tell what 'type' of null it is, since its underlying representation is simply all-zeros. See Boxing Nullable Types for more details.

bernd_rausch
  • 335
  • 2
  • 9
thecoop
  • 45,220
  • 19
  • 132
  • 189
  • Because b is first boxed to `int?` resulting in a null reference. – usr Oct 15 '12 at 13:58
  • Presumably you could do try { } catch { } to test it, so there IS a way of finding out. I bet using reflection you could take that a step further and polish it. Maybe initialise a new instance, which should give it a default value, and do `typeof(variable.value)` ? – NibblyPig Oct 15 '12 at 13:58
  • @SLC: You can't. It is just a null reference without type information. – usr Oct 15 '12 at 13:59
  • @SLC I've never seen a better explanation than this, from Microsoft's VP of the dev division (I don't remember what his title was when he wrote this): http://blogs.msdn.com/b/somasegar/archive/2005/08/11/450640.aspx – phoog Oct 15 '12 at 14:13
  • Actually, there is no underlying representation, any more than there's an underlying representation of `(string)null` or `(object)null`. – phoog Oct 15 '12 at 14:26
  • You are right, Nullables without value are boxed to null: http://msdn.microsoft.com/de-de/library/ms228597(v=vs.85). So I need to pass additional type info or use another approach to the problem. – bernd_rausch Oct 15 '12 at 17:24
3

conceptually, new Nullable<int> is null.

If we generalise, forgetting about Nullable<T>:

string s = null;
bool b = s is string;

we get false. false is the expected value for a type-check on a null value.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    What if he did `b = 3;`? If it's a string then you'd get an error, but if it was an int or nullable int you wouldn't get an error? – NibblyPig Oct 15 '12 at 14:02
1

You can try using Reflection to achieve this. Relevant article here.

Andrew
  • 815
  • 8
  • 17
  • 1
    You can't use reflection. Calling `GetType()` on a null reference will throw `NullReferenceException`. There is no type associated with the null reference. The article linked is based on types and not references to objects (which in this case may be null). – Martin Liversage Oct 15 '12 at 14:05
0

Unfortunately, null does not point to any specific memory location, and thus there is no metadata that you can associate with it to lookup the type. Thus, you cannot gain any additional information about the variable.

nickolayratchev
  • 1,136
  • 1
  • 6
  • 15
0

Unless I'm misunderstanding the question, you can get the type using GetType(). For example,

int? myNullableInt = null;
Console.WriteLine(myNullableInt.GetValueOrDefault().GetType());

If myNullableInt is null, a default value will be returned. Check the type of this returned value and, in this case, it will return System.Int32. You can do an If..else/Switch check on the returned type to perform the relevant action.

(int? is the same as Nullable<int>)

keyboardP
  • 68,824
  • 13
  • 156
  • 205
  • Or you could just call `Nullable.GetUnderlyingType()` – phoog Oct 15 '12 at 14:24
  • Or that. Either way, it does seem possible to get the information required in this question. – keyboardP Oct 15 '12 at 14:29
  • The problem is that I don't know whether the given object is a Nullable. It could also be a string or a plain int. I thought I could use the typecheck to get this information. But that doesn't seem to be the case. – bernd_rausch Oct 15 '12 at 16:29
  • @bernd_rausch Maybe this answer may help here http://stackoverflow.com/a/374663/187697 If it returns true, carry on with the code in my post, otherwise assume that it's not nullable and do a normal type check. – keyboardP Oct 15 '12 at 16:35
0

You can't do this, nor should you want to. Since Nullable<T> is a struct, value-type variables of this type have all the type information you need at compile time. Just use the typeof operator.

On the other hand, you might have a Nullable instance whose type you don't know at compile time. That would have to be a variable whose static type is object or some other reference type. Howver, because a Nullable<T> value boxes to a boxed T value, there's no such thing as a boxed Nullable<T>. That instance whose type your checking will just be a T.

This is why you get the same result for is int and is Nullable<int>. There's no way to distinguish between a boxed int and a boxed int?, because there is no boxed int?.

See Nulls not missing anymore for details.

phoog
  • 42,068
  • 6
  • 79
  • 117
0

As it has already been pointed out null has no type. To figure out if something is int? vs long? you need to use reflection to get information about something storing the type. Here is some code that you may be able to use as inspiration (not knowing exactly what you try to achieve the code is a bit weird):

class Pair<T> where T : struct {

  public Pair(T? a, T? b) {
    A = a;
    B = b;
  }

  public T? A { get; private set; }

  public T? B { get; private set; }

}

void DoSomething<T>(Pair<T> pair) where T : struct {
  DoMore(pair);
}

void DoMore(params object[] args) {
  Console.WriteLine("Do more");
  var nullableIntPairs = args.Where(IsNullableIntPair);
  foreach (Pair<int> pair in nullableIntPairs) {
    Console.WriteLine(pair.A);
    Console.WriteLine(pair.B);
  }
}

bool IsNullableIntPair(object arg) {
  var type = arg.GetType();
  return type.IsGenericType
    && type.GetGenericTypeDefinition() == typeof(Pair<>)
    && type.GetGenericArguments()[0] == typeof(int);
}

If you execute the following code

DoSomething(new Pair<int>(5, new int?()));
DoSomething(new Pair<long>(new long?(), 6L));

you get the following output:

Do more
5
null
Do more
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
0

You can use typeof :

a == typeof(Nullable<int>) //true
a == typeof(int) //false
Ema.H
  • 2,862
  • 3
  • 28
  • 41