IsGenericType, GetGenericTypeDefinition e Nullable.GetUnderlyingType

Asked

Viewed 112 times

1

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

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

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

Question where it was suggested.

1 answer

3


Has information about reflection here on the site.

Code types running on . NET have metadata various about its composition issued by the compiler.

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

One of the properties of this object is IsGenericType which as its name indicates is a boolean saying if the type you are checking is generic or not. If it is not generic it is obvious that it is not an voidable type since every voidable type needs to be contained within the object Nullable and closes due to short-Circuit.

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

If it is not an annulable type then you can take the type of this object that it is what you want.

But if the type is voidable you must pick the type that is inside the object Nullable. This is done with the method GetUnderlyingType(). We can translate the underlying as in "behind the scenes". So what will be picked up is the generic type of Nullable.

Quite simply the type Nullable is something like that:

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 on DataTable that’s the one value there. You have to configure the DataTable with his type and not with the 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");
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

  • Let me apply some situations to try to understand better. IsGenericType returns true if the type it is analyzing is something like int?, decimal?, List<int>, etc. And returns false if the type is int, string, decimal, etc. Now GetGenericTypeDefinition returns the generic "base" type used to create the final type, i.e. Dictionary<string, int> he returns Dictionary<TKey,TValue>. Comparing to C++, I give the generic type and it gives me back the template. That would be it?

  • What’s the difference between typeof(Nullable) and typeof(Nullable<>). I found some examples that use the first form.

  • 1

    The first is correct. The second is almost correct, in fact the name suffers a mangling and internally the name is different from what you know. C++ has no ready-made mechanism that does this, so you can’t compare. Note that all this is just simple information. No use <> picks up the guy without considering the genericity, and with <> picks up the generic type, as can be observed in what I did in the reply.

  • Understood. Actually when I quoted C++, I just wanted to illustrate what it would be like if C++ had something like this.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.