var x = int?+int?
int? r = int?+int?
niestety, tekst na forum nie ma szans oddac mojego zdziwienia;)
Wygląda na to, że pod tym dodawaniem kryją się dwie operacje
na pewno. wyglada mi to na bug/hiddenfeature w kompilatorze.: jesli kompilator w tym konkretnym przypadku nie zauwazalby 'explicit' na rzecz implicit, efekt bylby w 100% taki jak otrzymujemy przy kodzie z int? = czy var? = , ale nie tlumaczyloby to prawidlowego zachowania przy int =, chyba ze 'bug' jest az tak specyficzny..
Jednak przy próbie użycia własnej implementacji typu (..) jedyne co zmieniłem, to nazwę z
dlatego wlasnie mowie, ze Nullable<> jest traktowany bardzo specjalnie. W .Net jest wiele specjalnych typow - zerknij na klase System.Enum chociazby, ktorej dzieci (sic!) konstruowane sa w sliczny składniowo sposob, a ktora/ktore faktycznie sa jej dziecmi (choc kompilator tego zabrania komukolwiek) i zachowuja sie bardzo specyficznie (patrz nizej na zrzut z bebechow i na inicjalizacje pol skompilowanego enuma), albo na inne specjalne dziecko Objecta - na klase System.ValueType - ktora defacto jest rodzicem wszystkich struc'tur..
Nullable<> jest struktura i jest traktowane specjalnie przez kompilator, i przez CLR pewnie tez
Nie da się tego wykluczyć, ale dowód, który zaprezentowałeś niekoniecznie mnie przekonuje. "Non-nullable" wcale nie musi oznaczać, (..)
wiem, to byl pierwszy lepszy fakt jaki przyszedl mi do glowy, bez grzebania w bebechach. gdzies w ciemnych kątach pamieci majaczy mi, ze dlubiac reflektorem (acz ciezko porownywac inne poziomy 'niskosci'!) bo klasach ze standardowego .net i po tamtejszych genericach widzialem pare miejsc gdzie nullable byl jawnie traktowany specjalnie. natomiast reflektorem pieknie widac inne paskudne rzeczy, jakie kompilator robi, a jezyk sam w sobie nie pozwala --- np. ow enum i jego dzieci, delegaty, closure'y dla foreach/lambda/yieldreturn, ba, z tego co pamietam dziwy mozna reflektorem takze znalezc w system::string'u gdzie okazuje sie nagle, ze string wcale nie jest niemodyfikowalny!!
kurcze, jeszcze pol roku temu bylbym w stanie wskazac konkretne klasy i metody znajdowalne w oryginalnych assembliach .Net ktore lamia mozliwosci C#'a.. jedyne wytlumaczenie miejscami, to ze albo byly po prostu pisane w czyms innym (np. C++/CLI 0%native), albo ze mieli specjalna wersje kompilatora, albo -- ze kompilator ma jakies fajne undocumented switches..
Mało mi się to podoba, bo według mnie Microsoft powinien zaimplementować w języku odpowiednie mechanizmy, które umożliwiałyby implementację tego typu rzeczy w samym kodzie biblioteki, a nie w kodzie kompilatora czy CLR...
tak, zgadzam sie. to co tu widac jest wiec albo bugiem, albo cholerna niespojnoscia jezyka -- ostatecznie, nie po to definiuja klase nullable i 'alias' int?->nullable<int>, aby zostawiac niespojnosci.. jednak, trudno niezauwazyc faktu, ze struct Nullable jest specjalny podobnie jak Enum, dowod przytoczylem wczesniej, teraz w pelnej formie:
class X{};
struct Y{};
[Serializable]
public struct MyNullable<T> where T : struct //zywcem z metadanych + rename. bacz: struct MyNullable
{
public MyNullable(T value);
public static explicit operator T(T? value);
public static implicit operator T?(T value);
public bool HasValue { get; }
public T Value { get; }
public override bool Equals(object other);
public override int GetHashCode();
public T GetValueOrDefault();
public T GetValueOrDefault(T defaultValue);
public override string ToString();
}
X a = null; //poprawne
Y b = null; //niepoprawane
Nullable<int> c = null; //poprawne
int? d = null; //poprawne
MyNullable<int> e = null; //niepoprawane
to, co naprawde bylo w tym przykladzie z bledem 'non-nullable' najwazniejsze, to fakt, ze kompilator nie pozwala przypisywac null do zmiennych majacych typ struct (czego dowodzi blad dla przypisan zmiennych c oraz e) zas do strucktury Nullable pozwala!
jesli to Ciebie nie przekonuje o specjalnym traktowaniu niektorych typow czy konsturkcji, serio, prosze, wez Reflectora i zobacz co generuje kod:
enum Test{abc, def=2, ghi=-1}
(koniecznie wyswietl to jako C# a potem jako IL, poniewaz jako IL wyglada zupelnie inaczej..)
dla niezReflectorowanych:
'Test' stanie sie klasa '.class public auto ansi serializable sealed RegistryHive extends System.Enum'
'abc' stanie sie '.field public static literal valuetype Test abc = int32(0)'
'def' stanie sie '.field public static literal valuetype Test abc = int32(2)'
'ghi' stanie sie '.field public static literal valuetype Test abc = int32(-1)'
ah.. i jeszcze kompilator dorzuca na koniec:
'.field public specialname rtspecialname int32 value__'
ktorego normalnie w ogole nigdy nie zauwazasz, i ktore (w moim (z)rozumieniu) jest odpowiedzialne za mozliwosc wykonania w ogole przypisania jak powyzej "blahblah.. Test abc = int32(0)" i wewnetrznego przechowywania w obiektach klasy Test wartosci typu int32. tak w ogole, co to ma byc za przypisanie skoro ani Enum ani jego dziecko nie definiuja operatora konwersji/przypisania z int?:)
czyli, defacto, po skompilowanu Test wyglada mniejwiecej tak:
class Test : Enum
{
public const Test abc = 0; //przyp: const = 'static const' = 'literal' z c++/cli
public const Test def = 2;
public const Test ghi = -1;
public int value__;
}
i dlatego wlasnie w C# jak napiszesz potem "Test-kropka" to Intellisense powie Ci ze w Test sa pola "abc, def, ghi", ot zwykle podpowiedzenie static memberow klasy tyle ze z ikonkami innymi :)
i szczerze, nie sadze zeby w jakimkolwiek przyszlym .Net ten kod sie skompilowal z racji odwiecznej blokady na dziedziczenie po Enum, ktora juz sie pewnie domyslasz czemu jest nałożona..
edit/PS:
ogolnie, rozgadujac sie tak na ten temat, chcialem miedzy wierszami powiedziec, ze CLR / IL to jedno, a C# to drugie.. w IL mozna zdefiniowac bardzo bardzo wiele dziwacznych rzeczy. IL kompilowany wprost z samego siebie obsluguje wszystko, duza wiekszosc jest dostepna z poziomu C++/CLI pod postacia mniej lub bardziej dziwnych __ms_specific_keywords :), po stronie C# sporo juz jest zablokowane, jak np - kombinacje dozwolonych specyfikatorow widocznosci/wirtualnosci dla gettera/settera, mimo ze CLR/IL obsluguje praktycznie wszystkie mozliwe kombinacje poprawnie..