在C#
中,反射是否提供了一种确定某个给定的System.Type
类型是否模拟某个接口的方法?
public interface IMyInterface {}
public class MyType : IMyInterface {}
// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
在C#
中,反射是否提供了一种确定某个给定的System.Type
类型是否模拟某个接口的方法?
public interface IMyInterface {}
public class MyType : IMyInterface {}
// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
你有几个选择:
typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
typeof(MyType).GetInterface(nameof(IMyInterface)) != null
对于泛型接口,情况略有不同。
typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());
或者typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
someclass is IMyInterface
,因为这根本不涉及反射的成本。 因此,虽然不算错误,但这不是一种理想的方式。 - Arrya Reganis
检查继承层次结构的两个方向,而 IsAssignableFrom
仅向上检查。此外,如果您有一个对象实例,应该调用 IsInstanceOfType
(它也只向上查找)。 - Selloriois
只在一个方向上进行检查,否则new object() is string
将会是真。 - Jon Hanna使用 Type.IsAssignableTo
(从 .NET 5.0 开始):
typeof(MyType).IsAssignableTo(typeof(IMyInterface));
如几条评论所述,IsAssignableFrom可能因为“反向”的原因而被认为是令人困惑的。
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;
}
我认为这是正确的版本,有三个原因:
if(myObject is IMyInterface) {
// object myObject implements IMyInterface
}
要测试一个类型是否实现了某个接口:
if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
// type MyType implements IMyInterface
}
如果你有一个通用对象,并且想要进行强制转换以及检查被转换到的接口是否已经被实现,那么代码如下:
var myCastedObject = myObject as IMyInterface;
if(myCastedObject != null) {
// object myObject implements IMyInterface
}
if (myObject is IMyInterface myCastedObject) { ... }
。 - dimitar.bogdanovif (myObject is IMyInterface myCastedObject) { ... }
。 - undefined我刚刚做了:
public static bool Implements<I>(this Type source) where I : class
{
return typeof(I).IsAssignableFrom(source);
}
我希望我可以写成where I : Interface
,但是Interface
不是一种通用参数约束选项。使用class
是最接近的方式。
用法:
if(MyType.Implements<IInitializable>())
MyCollection.Initialize();
我只是说“实现”因为那更直观。我总是混淆IsAssignableFrom
。
return typeof(I).IsInterface && typeof(I).IsAssignableFrom(source)
来在方法的任何“不正确”使用上返回false,也就是说,在使用类类型而不是接口类型时,或者如果类型参数不是接口,则抛出异常。但是您可以争辩说派生类“实现”其父类... - Sindri Jóelsson正如其他人已经提到的: Benjamin Apr 10 '13在22:21"
不注意并将IsAssignableFrom的参数弄反了确实很容易。我现在会使用GetInterfaces:p -
另一种方法是创建一个简短的扩展方法,以某种程度上满足“最常见”的思考方式(同意这是一个非常小的个人选择,使其稍微“更自然”,基于个人的偏好):
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type type, Type assignableType)
{
return assignableType.IsAssignableFrom(type);
}
}
为什么不更泛化一些呢(不确定这是否真的有趣,但我认为我只是再添加一点“语法糖”):
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));
}
}
我认为这样可能更加自然,但再次强调,这只是个人意见:
var isTrue = michelleType.IsAssignableTo<IMaBelle>();
Boolean
=> bool
(我不知道为什么年轻时会有一些严格的“花哨”的编码规则)。 - Natalie Perret针对 Pierre Arnaud 的性能测试结果,优化 Jeff 的答案,如下所示:
var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;
Assembly
中实现某个接口的所有类型:var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
.Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);
IMyInterface<T>
,则此语句将始终返回 false
: typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>)) /* ALWAYS FALSE */
MyType
实现了IMyInterface<MyType>
,则以下代码可以正常工作并返回true
: typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))
然而,在运行时,您可能不知道类型参数T
。一个有点hacky(不太正式的)的解决方案是:
typeof(MyType).GetInterfaces()
.Any(x=>x.Name == typeof(IMyInterface<>).Name)
Jeff的解决方案稍微不太粗糙:
typeof(MyType).GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IMyInterface<>));
这是一种适用于任何情况的Type
扩展方法:
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);
}
}
typeof(MyType).IsImplementing(IMyInterface<>)
IsAssignableFrom(t1)
变体比GetInterfaces().Contains(t2)
相对应的方法快大约3倍。 - Pierre Arnaudtypeof(MyType).GetInterface(nameof(IMyInterface)) != null
来获得更好的类型安全性和重构能力。 - aholmes