Używając refleksji, w jaki sposób mogę uzyskać wszystkie typy, które implementują interfejs z C # 3.0 / .NET 3.5 z najmniejszym kodem i minimalizując iteracje?
Oto, co chcę ponownie napisać:
foreach (Type t in this.GetType().Assembly.GetTypes())
if (t is IMyInterface)
; //do stuff
Odpowiedzi:
Mój byłby to w c # 3.0 :)
Zasadniczo najmniejsza liczba iteracji zawsze będzie:
źródło
.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);
go odfiltrować (lubp.IsClass
).List<string>
nie implementuje,IEnumerable<object>
ale ta metoda zwróci true w .Net 4.0 z powodu kowariancji, która jest rzeczywiście błędna. Prawidłowa odpowiedź jest tutaj.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
To zadziałało dla mnie. Pętla przechodzi przez klasy i sprawdza, czy są one pobierane z mojego interfejsu
źródło
Aby znaleźć wszystkie typy w zestawie, które implementują interfejs IFoo:
Zauważ, że sugestia Ryana Rinaldiego była nieprawidłowa. Zwróci 0 typów. Nie możesz pisać
ponieważ typ jest instancją System.Type i nigdy nie będzie typu IFoo. Zamiast tego sprawdzasz, czy IFoo można przypisać z tego typu. To zapewni oczekiwane rezultaty.
Również sugestia Adama Wrighta, która jest obecnie oznaczona jako odpowiedź, jest również niepoprawna i z tego samego powodu. W czasie wykonywania powróci 0 typów, ponieważ wszystkie instancje System.Type nie były implementatorami IFoo.
źródło
Rozumiem, że to bardzo stare pytanie, ale pomyślałem, że dodam kolejną odpowiedź dla przyszłych użytkowników, ponieważ wszystkie dotychczasowe odpowiedzi wykorzystują jakąś formę
Assembly.GetTypes
.Chociaż GetTypes () rzeczywiście zwróci wszystkie typy, nie musi to oznaczać, że możesz je aktywować, a tym samym potencjalnie wyrzucić
ReflectionTypeLoadException
.Klasycznym przykładem braku możliwości aktywacji typu jest sytuacja, gdy zwracany typ pochodzi
derived
z zestawu,base
alebase
jest zdefiniowany w innym zestawie niż zestawderived
, do którego nie odwołuje się zestaw wywołujący.Powiedzmy, że mamy:
Jeśli w
ClassC
którym jestAssemblyC
, to robimy coś zgodnie z przyjętą odpowiedzią:Wtedy wyrzuci
ReflectionTypeLoadException
.To dlatego, że bez odniesienia do
AssemblyA
wAssemblyC
nie byłby w stanie:Innymi słowy
ClassB
nie można go załadować co jest sprawdzane i uruchamiane przez wywołanie GetTypes.Tak aby bezpiecznie zakwalifikować zestaw wyników dla ładowalnych typów wtedy jak na tym Phil Haacked artykule Get Wszystkie rodzaje w zespole i kod Jon Skeet byś zamiast zrobić coś takiego:
I wtedy:
źródło
CreateInstance
dla wszystkich, a wyjątek został zgłoszony, gdy próbowałem stworzyć rzeczywisty interfejs (co sprawiło, że pomyliłem się przez chwilę, gdy myślałem, że rzeczywisty interfejs nie działa w tym rozwiązaniu). Więc zmieniłem kod naGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
.Inne odpowiedzi tutaj
IsAssignableFrom
. Możesz także użyćFindInterfaces
zSystem
przestrzeni nazw, jak opisano tutaj .Oto przykład, który sprawdza wszystkie zestawy w aktualnie wykonywanym folderze zestawu, szukając klas, które implementują określony interfejs (unikając LINQ dla przejrzystości).
Możesz skonfigurować listę interfejsów, jeśli chcesz dopasować więcej niż jeden.
źródło
przeglądaj wszystkie załadowane zestawy, przeglądaj wszystkie ich typy i sprawdzaj, czy implementują interfejs.
coś jak:
źródło
To działało dla mnie (jeśli chcesz, możesz wykluczyć typy systemów podczas wyszukiwania):
źródło
Edycja: Właśnie widziałem edycję, aby wyjaśnić, że pierwotne pytanie dotyczyło ograniczenia iteracji / kodu i to wszystko dobrze i dobrze jako ćwiczenie, ale w rzeczywistych sytuacjach będziesz chciał najszybszej implementacji, niezależnie od tego jak fajnie wygląda bazowy LINQ.
Oto moja metoda Utils do iteracji wczytywanych typów. Obsługuje zarówno zwykłe klasy, jak i interfejsy, a opcja excludeSystemTypes znacznie przyspiesza działanie, jeśli szukasz implementacji we własnej bazie kodowej.
Przyznaję, że to nie jest ładne.
źródło
excludeSystemTypes
dwa razy w jednymif
?Inne odpowiedzi nie działały z ogólnym interfejsem .
W tym przypadku wystarczy zastąpić typeof (ISomeInterface) typof (T).
Więc z
otrzymujemy wszystkie zespoły
służy do wykluczenia interfejsu i abstrakcyjnych oraz
mieć je na liście.
źródło
Nie ma łatwego (pod względem wydajności) sposobu robienia tego, co chcesz.
Refleksja działa głównie z zespołami i typami, więc będziesz musiał uzyskać wszystkie typy zespołu i zapytać o odpowiedni interfejs. Oto przykład:
Otrzymasz wszystkie typy, które implementują interfejs IMyInterface w MyAssembly zespołu
źródło
Jeszcze lepiej przy wyborze miejsca montażu. Filtruj większość zestawów, jeśli wiesz, że wszystkie zaimplementowane interfejsy znajdują się w tym samym Assembly.DefinedTypes.
Przez Can Bilgin
źródło
Metodę OfType Linq można zastosować dokładnie w tego rodzaju scenariuszach:
https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8
źródło
Istnieje już wiele poprawnych odpowiedzi, ale chciałbym dodać inną implementację jako rozszerzenie typu i listę testów jednostkowych w celu zademonstrowania różnych scenariuszy:
Ten algorytm obsługuje następujące scenariusze:
źródło
źródło
Mam wyjątki w kodzie linq, więc robię to w ten sposób (bez skomplikowanego rozszerzenia):
źródło
Możesz użyć LINQ, aby uzyskać listę:
Ale czy naprawdę jest to bardziej czytelne?
źródło