Widziałem wiele osób używających następującego kodu:
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
Ale wiem, że możesz to zrobić:
if (obj1.GetType() == typeof(int))
// Some code here
Albo to:
if (obj1 is int)
// Some code here
Osobiście uważam, że ostatni jest najczystszy, ale czy czegoś mi brakuje? Który jest najlepszy w użyciu, czy jest to osobiste preferencje?
as
!as
nie jest tak naprawdę sprawdzaniem typów ...as
jest z pewnością formą sprawdzania typu, tak samo jakis
jest! Skutecznie wykorzystujeis
za kulisami i jest używany wszędzie w MSDN w miejscach, w których poprawia czystość kodu w porównaniu dois
. Zamiast sprawdzaniais
pierwszego, wywołanieas
ustanawia zmienną tekstową, która jest gotowa do użycia: Jeśli jest pusta, odpowiedz odpowiednio; w przeciwnym razie kontynuuj. Z pewnością coś, co widziałem i używałem całkiem sporo.as
/is
(omówionego na stackoverflow.com/a/27813381/477420 ), zakładając, że jego semantyczna praca dla twojego przypadku.GetType
Sposób łączysz się jestSystem.Reflection.Assembly
- zupełnie inny sposób i bez znaczenia tutaj.Odpowiedzi:
Wszystkie są różne.
typeof
przyjmuje nazwę typu (którą określasz podczas kompilacji).GetType
pobiera typ środowiska wykonawczego instancji.is
zwraca true, jeśli instancja znajduje się w drzewie dziedziczenia.Przykład
Tak. T jest zawsze rodzajem wyrażenia. Pamiętaj, że metoda ogólna to w zasadzie cała masa metod odpowiedniego typu. Przykład:
źródło
new Dog().GetType() is Animal
zwraca wartość false (a także twoją inną wersję), ponieważ.GetType()
zwraca obiekt typuType
iType
nie jestAnimal
.Użyj,
typeof
jeśli chcesz uzyskać typ w czasie kompilacji . Użyj,GetType
jeśli chcesz uzyskać typ w czasie wykonywania . Rzadko są jakieś przypadki do użycia,is
ponieważ wykonuje rzutowanie, aw większości przypadków i tak rzucasz zmienną.Istnieje czwarta opcja, której nie wziąłeś pod uwagę (szczególnie jeśli zamierzasz rzucić obiekt również na typ, który znajdziesz); to jest do użycia
as
.To używa tylko jednej obsady,
podczas gdy takie podejście:wymaga dwóch .Aktualizacja (styczeń 2020):
Przykład:
źródło
is
nadal wykonuje rzutowanie?typeof()
, a ta odpowiedź nie sugeruje, że możesz. Zamiast tego podajesz typ, tzn.typeof(string)
Działa,typeof("foo")
nie.is
wykonuje się obsada jako taka, raczej specjalna operacja w IL.if (obj is Foo foo) { /* use foo here */ }
1.
Jest to nielegalne, ponieważ
typeof
działa tylko na typach, a nie na zmiennych. Zakładam, że obj1 jest zmienną. W ten sposóbtypeof
jest statyczny i działa w czasie kompilacji zamiast w środowisku wykonawczym.2)
To jest,
true
jeśliobj1
jest dokładnie typuint
. Jeśliobj1
pochodzi odint
, warunek if będziefalse
.3)
Dzieje się tak,
true
jeśliobj1
jestint
, lub jeśli pochodzi od klasy o nazwieint
, lub jeśli implementuje interfejs o nazwieint
.źródło
To jest błąd. Operator typeof w języku C # może przyjmować tylko nazwy typów, a nie obiekty.
To zadziała, ale może nie tak, jak można się spodziewać. W przypadku typów wartości, jak pokazano tutaj, jest to akceptowalne, ale dla typów referencyjnych zwróciłoby wartość true tylko wtedy, gdy typ był dokładnie tego samego typu, a nie coś innego w hierarchii dziedziczenia. Na przykład:
Byłoby to wydrukować
"o is something else"
, ponieważ typo
jestDog
, nieAnimal
. Możesz jednak sprawić, aby to zadziałało, jeśli użyjeszIsAssignableFrom
metodyType
klasy.Ta technika wciąż jednak stanowi poważny problem. Jeśli twoja zmienna ma wartość NULL, wywołanie
GetType()
to wyrzuci NullReferenceException. Aby więc działało poprawnie, wykonaj następujące czynności:Dzięki temu masz równoważne zachowanie
is
słowa kluczowego. Dlatego jeśli takie zachowanie jest pożądane, należy użyćis
słowa kluczowego, które jest bardziej czytelne i wydajniejsze.Jednak w większości przypadków
is
słowo kluczowe nadal nie jest tym, czego naprawdę chcesz, ponieważ zwykle nie wystarczy po prostu wiedzieć, że obiekt jest określonego typu. Zwykle chcesz faktycznie użyć tego obiektu jako instancji tego typu, co również wymaga jego rzutowania. I może się okazać, że piszesz taki kod:Ale to powoduje, że CLR sprawdza typ obiektu maksymalnie dwa razy. Sprawdzi to raz, aby zadowolić
is
operatora, a jeślio
takAnimal
, to sprawdzimy ponownie, aby zweryfikować rzut.Zamiast tego bardziej efektywnie jest to zrobić:
as
Operator jest obsada, że nie rzuci wyjątek, jeśli to się nie powiedzie, zamiast wracaćnull
. W ten sposób CLR sprawdza typ obiektu tylko raz, a następnie musimy po prostu sprawdzić zero, co jest bardziej wydajne.Ale uwaga: wiele osób wpada w pułapkę
as
. Ponieważ nie rzuca wyjątków, niektórzy uważają go za „bezpieczną” obsadę i używają jej wyłącznie, unikając regularnych rzutów. Prowadzi to do takich błędów:W tym przypadku, deweloper jest wyraźnie zakładając, że
o
będzie zawsze byćAnimal
, i tak długo, jak ich założenie jest słuszne, wszystko działa bez zarzutu. Ale jeśli się mylą, to kończą się tutajNullReferenceException
. W przypadku zwykłej obsady otrzymalibyInvalidCastException
zamiast tego, co bardziej poprawnie zidentyfikowałoby problem.Czasami ten błąd może być trudny do znalezienia:
Jest to kolejny przypadek, w którym deweloper wyraźnie spodziewa
o
się zaAnimal
każdym razem, ale nie jest to oczywiste w konstruktorze, w którymas
używana jest obsada. Nie jest to oczywiste, dopóki nie przejdziesz doInteract
metody, w którejanimal
pole ma zostać pozytywnie przypisane. W tym przypadku nie tylko trafiasz na wprowadzający w błąd wyjątek, ale jest on zgłaszany dopiero potencjalnie znacznie później niż wtedy, gdy wystąpił rzeczywisty błąd.W podsumowaniu:
Jeśli potrzebujesz tylko wiedzieć, czy obiekt jest jakiegoś typu, użyj
is
.Jeśli musisz traktować obiekt jako instancję określonego typu, ale nie wiesz na pewno, że obiekt będzie tego typu, użyj
as
i sprawdźnull
.Jeśli chcesz traktować obiekt jako instancję określonego typu, a obiekt ma być tego typu, użyj zwykłego rzutowania.
źródło
o is Animal
wymaga CLR, aby sprawdzić, czy typ zmiennejo
toAnimal
. Po raz drugi sprawdza, kiedy rzuca oświadczenie((Animal)o).Speak()
. Zamiast sprawdzać dwa razy, sprawdź raz za pomocąas
.Jeśli używasz C # 7, nadszedł czas na aktualizację świetnej odpowiedzi Andrew Hare. Dopasowanie wzorca wprowadziło ładny skrót, który daje nam zmienną tekstową w kontekście instrukcji if, bez konieczności oddzielnej deklaracji / rzutowania i sprawdzenia:
Wygląda to dość rozczarowująco dla jednej takiej obsady, ale naprawdę świeci, gdy masz wiele możliwych typów wchodzących w twoją rutynę. Poniżej znajduje się stary sposób na uniknięcie dwukrotnego rzucenia:
Praca nad zmniejszaniem tego kodu w jak największym stopniu, a także unikaniem duplikatów rzutów tego samego obiektu zawsze mnie niepokoiła. Powyższe jest ładnie skompresowane z dopasowaniem wzorca do następujących:
EDYCJA: Zaktualizowano dłuższą nową metodę używania przełącznika zgodnie z komentarzem Palec.
źródło
switch
instrukcji z dopasowaniem wzorca .if (obj1 is int integerValue) { integerValue++; }
Miałem
Type
właściwość do porównania i nie mogłem używaćis
(jakmy_type is _BaseTypetoLookFor
), ale mogłem użyć tych:Zauważ to
IsInstanceOfType
iIsAssignableFrom
zwróćtrue
, porównując te same typy, do których zwróci IsSubClassOffalse
. IIsSubclassOf
nie działa na interfejsach, na których działają pozostałe dwa. (Zobacz także to pytanie i odpowiedź ).źródło
Wolę to
Mimo to, jeśli używasz jest , jesteś prawdopodobnie nie prawidłowo za pomocą dziedziczenia.
Załóżmy, że osoba: istota i to zwierzę: istota. Kanał jest wirtualną metodą w Entity (aby uszczęśliwić Neila)
Raczej
źródło
Uważam, że ostatni dotyczy również dziedziczenia (np. Pies to zwierzę == prawda), co w większości przypadków jest lepsze.
źródło
To zależy od tego, co robię. Jeśli potrzebuję wartości bool (powiedzmy, aby ustalić, czy rzuciłem na int), użyję
is
. Jeśli rzeczywiście potrzebuję tego typu z jakiegoś powodu (powiedzmy, aby przejść do innej metody) użyjęGetType()
.źródło
Ostatni jest czystszy, bardziej oczywisty, a także sprawdza podtypy. Inni nie sprawdzają polimorfizmu.
źródło
Służy do uzyskania obiektu System.Type dla typu. Wyrażenie typeof przybiera następującą postać:
W tym przykładzie użyto metody GetType, aby określić typ, który jest używany do przechowywania wyniku obliczeń numerycznych. Zależy to od wymagań dotyczących przechowywania wynikowej liczby.
źródło
źródło
Możesz użyć operatora „typeof ()” w języku C #, ale musisz wywołać przestrzeń nazw przy użyciu System.IO; Musisz użyć słowa kluczowego „is”, jeśli chcesz sprawdzić typ.
źródło
typeof
nie jest zdefiniowany w przestrzeni nazw, jest to słowo kluczowe.System.IO
nie ma z tym nic wspólnego.Test wydajności typeof () vs GetType ():
Wyniki w trybie debugowania:
Wyniki w trybie zwolnienia:
źródło
DateTime
nie należy go używać, jeśli obawiasz się czasów poniżej 100 ms , ponieważ wykorzystuje on ramy czasowe systemu operacyjnego. Porównując zStopwatch
, która wykorzystuje procesoryTick
, rozdzielczość używana przez aDateTime
w Win7 to aż 15 ms.