Bietet Reflektion in C#
eine Möglichkeit zu bestimmen, ob ein bestimmter System.Type
Typ eine Schnittstelle modelliert?
public interface IMyInterface {}
public class MyType : IMyInterface {}
// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
Sie haben ein paar Möglichkeiten aus meinem Kopf
typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
Bei einer generischen Schnittstelle ist das etwas anders.
typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))
Verwenden Sie Type.IsAssignableFrom
:
_typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
_
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());
oder
typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
public static bool ImplementsInterface( this Type type, Type ifaceType ) {
Type[] intf = type.GetInterfaces();
for ( int i = 0; i < intf.Length; i++ ) {
if ( intf[ i ] == ifaceType ) {
return true;
}
}
return false;
}
Ich denke, dies ist aus drei Gründen die richtige Version:
1) Es verwendet GetInterfaces und nicht IsAssignableFrom. Es ist schneller, da IsAssignableFrom nach mehreren Überprüfungen GetInterfaces aufruft.
2) Es wird über das lokale Array iteriert, sodass keine Grenzüberprüfungen stattfinden.
3) Es wird der für Type definierte Operator == verwendet, der wahrscheinlich sicherer ist als die Equals-Methode (die der Contains-Aufruf eventuell verwenden wird).
Ich habe gerade getan:
public static bool Implements<I>(this Type source) where I : class
{
return typeof(I).IsAssignableFrom(source);
}
Ich wünschte, ich hätte where I : interface
sagen können, aber interface
ist keine generische Option für Parameterbeschränkungen. class
ist so nah wie möglich.
Verwendungszweck:
if(MyType.Implements<IInitializable>())
MyCollection.Initialize();
Ich habe gerade Implements
gesagt, weil das intuitiver ist. Ich bekomme immer IsAssignableFrom
Flip-Flops.
Wie schon jemand anderes erwähnt: Benjamin 10.04.13 um 22:21 "
Es war sicher einfach, nicht darauf zu achten und die Argumente für IsAssignableFrom rückwärts abzurufen. Ich werde jetzt mit GetInterfaces gehen: p -
Nun, eine andere Möglichkeit besteht darin, eine kurze Erweiterungsmethode zu erstellen, die in gewissem Maße die "üblichste" Denkweise erfüllt (und darin, dass dies eine sehr kleine persönliche Entscheidung ist, die es etwas "natürlicher" macht, je nach den eigenen Vorlieben ):
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type type, Type assignableType)
{
return assignableType.IsAssignableFrom(type);
}
}
Und warum nicht ein bisschen generischer werden (na ja, ich bin mir nicht sicher, ob es wirklich so interessant ist, na ja, ich gehe davon aus, dass ich nur eine weitere Prise Syntaxing-Zucker übergebe):
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type type, Type assignableType)
{
return assignableType.IsAssignableFrom(type);
}
public static bool IsAssignableTo<TAssignable>(this Type type)
{
return IsAssignableTo(type, typeof(TAssignable));
}
}
Ich denke, dass es auf diese Weise viel natürlicher ist, aber auch hier ist es nur eine Frage sehr persönlicher Meinungen:
var isTrue = michelleType.IsAssignableTo<IMaBelle>();
Änderung von Jeffs Antwort für optimale Leistung (dank Leistungstest von Pierre Arnaud):
var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;
So finden Sie alle Typen, die eine Schnittstelle in einem bestimmten Assembly
implementieren:
var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
.Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);
IsAssignableFrom
wird jetzt in TypeInfo
verschoben:
typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());
Eine richtige Antwort ist
typeof(MyType).GetInterface(nameof(IMyInterface)) != null;
Jedoch,
typeof(MyType).IsAssignableFrom(typeof(IMyInterface));
gibt möglicherweise ein falsches Ergebnis zurück, wie der folgende Code mit string und IConvertible zeigt:
static void TestIConvertible()
{
string test = "test";
Type stringType = typeof(string); // or test.GetType();
bool isConvertibleDirect = test is IConvertible;
bool isConvertibleTypeAssignable = stringType.IsAssignableFrom(typeof(IConvertible));
bool isConvertibleHasInterface = stringType.GetInterface(nameof(IConvertible)) != null;
Console.WriteLine($"isConvertibleDirect: {isConvertibleDirect}");
Console.WriteLine($"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}");
Console.WriteLine($"isConvertibleHasInterface: {isConvertibleHasInterface}");
}
Ergebnisse:
isConvertibleDirect: True
isConvertibleTypeAssignable: False
isConvertibleHasInterface: True
Wie wäre es mit
typeof(IWhatever).GetTypeInfo().IsInterface
Beachten Sie, dass wenn Sie eine generische Schnittstelle IMyInterface<T>
haben, diese immer false
zurückgibt:
typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */
Das funktioniert auch nicht:
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>)) /* ALWAYS FALSE */
Wenn jedoch MyType
IMyInterface<MyType>
implementiert, funktioniert dies und gibt true
zurück:
typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))
Wahrscheinlich kennen Sie den Typparameter T
jedoch zur Laufzeit nicht . Eine etwas hackige Lösung ist:
typeof(MyType).GetInterfaces()
.Any(x=>x.Name == typeof(IMyInterface<>).Name)
Jeffs Lösung ist ein bisschen weniger hackig:
typeof(MyType).GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IMyInterface<>));
Hier ist eine Erweiterungsmethode für Type
, die auf jeden Fall funktioniert:
public static class TypeExtensions
{
public static bool IsImplementing(this Type type, Type someInterface)
{
return type.GetInterfaces()
.Any(i => i == someInterface
|| i.IsGenericType
&& i.GetGenericTypeDefinition() == someInterface);
}
}
(Beachten Sie, dass im obigen Beispiel linq verwendet wird, das wahrscheinlich langsamer als eine Schleife ist.)
Sie können dann Folgendes tun:
typeof(MyType).IsImplementing(IMyInterface<>)
Wenn Sie einen Typ oder eine Instanz haben, können Sie leicht überprüfen, ob diese eine bestimmte Schnittstelle unterstützen.
So testen Sie, ob ein Objekt eine bestimmte Schnittstelle implementiert:
if(myObject is IMyInterface) {
// object myObject implements IMyInterface
}
So testen Sie, ob ein Typ eine bestimmte Schnittstelle implementiert:
if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
// type MyType implements IMyInterface
}
Wenn Sie ein generisches Objekt haben und eine Umwandlung durchführen möchten sowie prüfen möchten, ob die Schnittstelle, in die Sie die Umwandlung durchführen, implementiert ist, lautet der Code:
var myCastedObject = myObject as IMyInterface;
if(myCastedObject != null) {
// object myObject implements IMyInterface
}