Mam w swoim projekcie klasę ogólną z klasami pochodnymi.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
Czy jest jakiś sposób, aby dowiedzieć się, czy Type
obiekt pochodzi GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
nie działa.
c#
generics
reflection
Bernhardrusch
źródło
źródło
(Przesłane z powodu ogromnego przepisywania)
Odpowiedź kodu JaredPara jest fantastyczna, ale mam wskazówkę, która sprawiłaby, że niepotrzebne byłoby, gdyby typy ogólne nie były oparte na parametrach typu wartości. Nie wiedziałem, dlaczego operator „jest” nie działa, więc udokumentowałem również wyniki moich eksperymentów do wykorzystania w przyszłości. Popraw tę odpowiedź, aby jeszcze bardziej zwiększyć jej przejrzystość.
WSKAZÓWKA:
Jeśli upewnisz się, że twoja implementacja GenericClass dziedziczy po abstrakcyjnej nieogólnej klasie podstawowej, takiej jak GenericClassBase, możesz zadać to samo pytanie bez żadnych problemów w następujący sposób:
IsSubclassOf ()
Moje testy wskazują, że IsSubclassOf () nie działa na typach ogólnych bez parametrów, takich jak
podczas gdy będzie działać
Dlatego poniższy kod będzie działał dla dowolnej pochodnej GenericClass <>, zakładając, że chcesz przetestować na podstawie SomeType:
Jedyny raz, kiedy mogę sobie wyobrazić, że chciałbyś przetestować przez GenericClass <>, to scenariusz wtyczki.
Myśli o operatorze „jest”
W czasie projektowania C # nie zezwala na stosowanie bezparametrowych danych generycznych, ponieważ zasadniczo nie są one w tym momencie kompletnym typem CLR. Dlatego musisz zadeklarować zmienne ogólne za pomocą parametrów i dlatego operator „jest” jest tak potężny do pracy z obiektami. Nawiasem mówiąc, operator „jest” również nie może oceniać ogólnych parametrów bez parametrów.
Operator „jest” przetestuje cały łańcuch dziedziczenia, w tym interfejsy.
Tak więc, biorąc pod uwagę instancję dowolnego obiektu, następująca metoda załatwi sprawę:
Jest to trochę zbędne, ale pomyślałem, że pójdę naprzód i zwizualizuję to dla wszystkich.
Dany
Poniższe wiersze kodu zwrócą wartość true:
Z drugiej strony, jeśli chcesz coś specyficznego dla GenericClass, możesz uczynić to bardziej szczegółowym, tak myślę, tak:
Następnie przetestowałbyś w ten sposób:
źródło
Type
przedmiot.typeof
operatora. Zgodnie z dokumentacją: „Operator typeof służy do uzyskania obiektu System.Type dla typu”.Przebadałem niektóre z tych próbek i okazało się, że w niektórych przypadkach ich brakowało. Ta wersja działa z wszystkimi rodzajami ogólnych: typów, interfejsów i ich definicji typów.
Oto również testy jednostkowe:
źródło
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
zastępujesz więc tę zmienną rozszerzeniem instrukcji if:if (parent.IsGenericType && shouldUseGenericType)
i dostajesz to,if (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
co następnie redukuje się doif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
tego, czy moje referencje są równe, a wartość równa się pomieszaniu? Myślałem, że istnieje tylko jedna instancja każdego typu w pamięci, więc dwie zmienne wskazujące ten sam typ w rzeczywistości wskazują na to samo miejsce w pamięci.Wydaje mi się, że ta implementacja działa w większej liczbie przypadków (klasa ogólna i interfejs z zainicjowanymi parametrami lub bez nich, niezależnie od liczby elementów potomnych i parametrów):
Oto moje
7076 przypadków testowych:Klasy i interfejsy do testowania:
źródło
Kod JaredPara działa, ale tylko dla jednego poziomu dziedziczenia. Aby uzyskać nieograniczone poziomy dziedziczenia, użyj następującego kodu
źródło
while
w JaredPar obejmuje nieograniczoną liczbę poziomów.Oto mała metoda, którą stworzyłem, aby sprawdzić, czy obiekt pochodzi od określonego typu. Działa świetnie dla mnie!
źródło
Może to być przesada, ale używam metod rozszerzenia takich jak poniżej. Sprawdzają interfejsy oraz podklasy. Może również zwrócić typ, który ma określoną definicję ogólną.
Na przykład na przykład w pytaniu może testować zarówno ogólny interfejs, jak i ogólną klasę. Zwracanego typu można użyć
GetGenericArguments
do określenia, czy ogólny typ argumentu to „SomeType”.źródło
Opierając się na doskonałej odpowiedzi powyżej autorstwa fir3rpho3nixx i Davida Schmitta, zmodyfikowałem ich kod i dodałem test ShouldInheritOrImplementTypedGenericInterface (ostatni).
źródło
Wszystko to można łatwo zrobić za pomocą linq. Znajdzie to wszystkie typy, które są podklasą ogólnej klasy bazowej GenericBaseType.
źródło
Proste rozwiązanie: po prostu utwórz i dodaj drugi, nietypowy interfejs do klasy ogólnej:
Następnie wystarczy sprawdzić, że w żaden sposób, jak za pomocą
is
,as
,IsAssignableFrom
, itd.Oczywiście możliwe tylko wtedy, gdy masz możliwość edycji klasy ogólnej (którą wydaje się mieć OP), ale jest to nieco bardziej eleganckie i czytelne niż przy użyciu kryptycznej metody rozszerzenia.
źródło
IGenericClass
, nie zagwarantuje ci tego,GenericClass
aniGenericInterface
też nie zostanie rozszerzone lub zaimplementowane. Oznacza to, że twój kompilator również nie pozwoli ci uzyskać dostępu do żadnych członków klasy ogólnej.Dodano do odpowiedzi @ jaredpar, oto czego używam do sprawdzania interfejsów:
Dawny:
źródło
JaredPar,
Nie działało to dla mnie, jeśli przekażę typeof (type <>) jako toCheck. Oto co zmieniłem.
źródło
typeof(type<>)
jako astoCheck
. Ponadto naprawdę potrzebujesz zerowego czeku, jak w rozwiązaniu JaredPar. Co więcej, nie wiem, co jeszcze osiągniesz, zastępująccur == generic
w jego rozwiązaniucur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
inne niż ograniczenie metody do pracy tylko dla typów ogólnych. Innymi słowy, coś takiego kończy się niepowodzeniem z wyjątkiem:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll - odpowiedź Anandy Gopal jest interesująca, ale w przypadku, gdy instancja nie zostanie wcześniej utworzona lub chcesz sprawdzić za pomocą definicji typu ogólnego, sugeruję następującą metodę:
i używaj go w następujący sposób:
Istnieją cztery przypadki, gdy zarówno warunkowe
t
(do testowania) id
są typy generyczne i dwa przypadki są objętet==d
które są (1) anit
też nied
jest ogólną definicję lub (2), obie z nich są definicje rodzajowe . Pozostałe przypadki są jedną z nich, jest to ogólna definicja, tylko gdyd
jest to już ogólna definicja, mamy szansę powiedzieć, że at
jest,d
ale nie odwrotnie.Powinien współpracować z dowolnymi klasami lub interfejsami, które chcesz przetestować, i zwraca to tak, jakbyś testował instancję tego typu z
is
operatorem.źródło
źródło
Możesz wypróbować to rozszerzenie
źródło
spóźniony do gry w tej sprawie ... ja też mam inną permutację odpowiedzi JarodPara.
oto Type.IsSubClassOf (Type) dzięki uprzejmości reflektora:
po tym widzimy, że nie robi nic zbyt cray cray i jest podobny do iteracyjnego podejścia JaredPara. na razie w porządku. oto moja wersja (zastrzeżenie: nie zostało dokładnie przetestowane, więc daj znać, jeśli znajdziesz problemy)
w zasadzie jest to tylko metoda rozszerzenia System.Type - zrobiłem to, aby celowo ograniczyć typ „thisType” do konkretnych typów, ponieważ moje bezpośrednie użycie to zapytanie LINQ „gdzie” predykuje względem obiektów Type. jestem pewien, że wszyscy sprytni ludzie mogliby go sprowadzić do wydajnej, uniwersalnej metody statycznej, jeśli zajdzie taka potrzeba :) kod robi kilka rzeczy, kod nie odpowiada
reszta jest w zasadzie taka sama jak kod JaredPara
źródło