2015-05-29 17 views
9

Spójrz na przykładowy kod poniżejActivator.CreateInstance tworzy wartość typu T zamiast Nullable <T>

var genericNullableType = typeof(Nullable<>); 
var nullableType = genericNullableType.MakeGenericType(typeof(bool)); 
var returnValue = Activator.CreateInstance(nullableType, (object)false); 

Dla niektórych zmiennej powodem returnValue będzie od rodzaju bool a nie bool?. Dlaczego tak jest i jak można tego uniknąć?

UPD: Oto zrzut ekranu z mojego VS enter image description here

+0

@petelids Używam VS 2013 Premium i .NET Framework 4.5 i kompilacji budowania jest Debugowanie. Czy używasz tej samej konfiguracji? – Demarsch

+1

Nie jest to jednoznaczne z 'Aktywatorem'. 'Console.WriteLine ((nowy Nullable (false) .GetType(). FullName));' również wypluwa zwykły Boolean. – vcsjones

+1

Nie ma sposobu, aby uzyskać pudełko o zerowej wartości. Środowisko wykonawcze ma specjalną obsługę dla boksowania zerowego i zawsze odwija ​​go do wartości pudełkowej typu bazowego lub odwołania zerowego. To znaczy, że powinno to być możliwe do rzucenia jako "bool", więc nie jestem pewien, czego szukasz. –

Odpowiedz

15

W tym konkretnym przypadku używasz przeciążenie CreateInstance która zwraca object. Model Nullable<T> jest oznaczony jako , dlatego należy go przedstawić w postaci pudełkowej. Jednak Nullable<T> nie może być w rzeczywistości zapakowany zgodnie z regułami CLR. Zamiast tego używana jest wartość bazowa lub null. Dlatego zamiast tego otrzymujesz surowy bool zamiast bool?.

Dokumentacja: https://msdn.microsoft.com/en-us/library/ms228597.aspx

EDIT

Wydaje się, że pewne zamieszanie wokół ustalania, czy rodzaj wartości jest pustych lub nie. W szczególności to zostało podkreślone, że następujące druki System.Boolean i nie System.Nullable``1[System.Boolean]:

var x = (bool?)true; 
Console.WriteLine(x.GetType()); 

Kod ten jest również ofiarą do boksu. Wezwanie do GetType ma niejawny operację boks, ponieważ jest to wywołanie metody wirtualnego na object, a nie sposób na Nullable<T>:

IL_0009: ldloc.0 
IL_000a: box valuetype [mscorlib]System.Nullable`1<bool> 
IL_000f: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() 
IL_0014: call void [mscorlib]System.Console::WriteLine(object) 

Najbezpieczniej wydrukować rzeczywistego typu wartości var to zrobić po podstęp z generics:

static void PrintType<T>(T value) 
{ 
    Console.WriteLine(typeof(T)); 
} 

PrintType(x); // Prints System.Nullable`1[System.Boolean] 
+0

Nawet jeśli inny przeładowanie CreateInstance zostało użyte, GetType nadal będzie wewnętrznie, ponieważ nie jest wirtualne, więc nigdy nie zobaczysz 'Nullable ' z GetType, prawda? –

+0

@mikez correct. Wywołanie funkcji 'GetType()' generuje niejawny kod '.box' il, który zapobiega wypluwaniu typu nullable. Aby uzyskać prawdziwy typ do wydrukowania, należy użyć generycznych. Pokaże to w ciągu sekundy. – JaredPar