IsGenericType, GetGenericTypeDefinition, and Nullable.GetUnderlyingType

1

In a snippet of code I was suggested to use these three members in order to check if the properties of an object are Nullable .

p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition ( ) == typeof( Nullable<> ) ? Nullable.GetUnderlyingType ( p.PropertyType ) : p.PropertyType

I could not find a satisfactory explanation about these members, IsGenericType, GetGenericTypeDefinition e Nullable.GetUnderlyingType , I do not quite understand what they return. The documentation was not enough for my understanding.

Question where it was suggested.

    
asked by anonymous 19.02.2017 / 00:22

1 answer

3

You have reflection information here on the site .

Code types running in .NET have various metadata about their compiler rendering.

You can access this data using the GetType() or operator typeof will return an object Type .

One of the properties of this object is IsGenericType which as its name indicates is a Boolean saying whether the type you are checking is generic or not. If it is not generic it is obvious that it is not a nullable type since every nullable type must be contained within the object Nullable " and quits because of the short-circuit .

If it is generic then it passes to the next one where it specifically checks to see if the GetGenericTypeDefinition() method returns the same type as Nullable , indicating that type is nullable .

If it is not a nullable type then you can get the type of this object that it is what you want.

But if the type is nullable you should get the type that is inside the object Nullable . This is done with the method GetUnderlyingType() . . We can translate the underlying as "underneath the cloths". So what will be caught is the generic type of Nullable .

Well simplified type Nullable looks something like this:

struct Nullable<T> when T : struct {
    bool HasValue; //determina se esse objeto é nulo ou não
    T value; //é o objeto que lhe interessa de fato
    //tem mais um monte de coisa aqui, inclusive o método GetUnderlyingType()
}

What you want to put in DataTable is this value there. You have to set DataTable to its type and not to type Nullable .

using static System.Console;
using System.Collections.Generic;
using System;

public class Program {
    public static void Main() {
        WriteLine(typeof(Nullable).Name);
        WriteLine(typeof(Nullable<>).Name);
        int? nInt = 0;
        decimal? nDecimal = 0M;
        List<int> lInt = new List<int>();
        int xInt = 1;
        string xString = "";
        decimal xDecimal = 2M;
        Dictionary<string, int> dStingInt = new Dictionary<string, int>();
        PrintObject<int?>(nInt);
        PrintObject<decimal?>(nDecimal);
        PrintObject<List<int>>(lInt);
        PrintObject<int>(xInt);
        PrintObject<string>(xString);
        PrintObject<decimal>(xDecimal);
        PrintObject<Dictionary<string, int>>(dStingInt);
    }
    private static void PrintObject<T>(T obj) {
        var type = typeof(T); 
        var generic = type.IsGenericType;
        var nullable = generic && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        WriteLine($"{type.Name} - {type.IsGenericType} - {(generic ? type.GetGenericTypeDefinition().Name : (""))} - {(nullable ? Nullable.GetUnderlyingType(type).Name : (""))} - {type.Name}\n");
    }
}

See running on .NET Fiddle . And No Coding Ground . Also put it on GitHub for future reference .

    
19.02.2017 / 01:01