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 likeint?
,decimal?
,List<int>
, etc. And returns false if the type isint
,string
,decimal
, etc. NowGetGenericTypeDefinition
returns the generic "base" type used to create the final type, i.e.Dictionary<string, int>
he returnsDictionary<TKey,TValue>
. Comparing to C++, I give the generic type and it gives me back the template. That would be it?– Matheus Saraiva
What’s the difference between
typeof(Nullable)
andtypeof(Nullable<>)
. I found some examples that use the first form.– Matheus Saraiva
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.– Maniero
Understood. Actually when I quoted C++, I just wanted to illustrate what it would be like if C++ had something like this.
– Matheus Saraiva