见此截图
它显示所有定义的类型都是RuntimeType
,然后我使用myType.IsAssignableFrom(definedType)
,它永远不会返回true
。
这是可以理解的,因为它是RuntimeType
,但我如何从中获取实际类型。
public static List<T> GetAllDerivedTypes<T>(this Assembly assembly)
{
var type = typeof(T);
var isInterface = type.IsInterface;
var name = type.Name;
if (!isInterface)
{
throw new Exception("Not an interface type");
}
List<object> types = new List<object>();
foreach (var definedType in assembly.DefinedTypes)
{
var isAssignableFrom = definedType.IsAssignableFrom(type);
var interfaces = definedType.ImplementedInterfaces.Where(x => x.Name == name);
if (isAssignableFrom)
{
types.Add(definedType);
}
}
return types.Cast<T>().ToList();
}
我可以轻松地将其减少到一个Linq
语句,但我已经把它搞砸了,所以我可以看到出了什么问题。它永远不会返回T
的所有派生类型T : interface
。
答案 0 :(得分:1)
您正在以错误的方式调用方法调用。阅读https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom(v=vs.110).aspx。如果type是从definedType派生的,那么definedType.IsAssignableFrom(type)
将返回true,你希望反过来。
来自文档:
public virtual bool IsAssignableFrom(Type c)
如果满足以下任何条件,则返回true:
所以请将您的电话改为:
var isAssignableFrom = type.IsAssignableFrom(definedType);
答案 1 :(得分:-1)
Chris已经回答了您使用错误顺序的IsAssignableFrom
这一事实。您想调用typeof(T).IsAssignableFrom(definedType)
以检查是否可以将definedType
类型的对象分配给T
类型的变量。
但是你的代码还存在另一个问题,我已经将其缩小到了这个问题,希望强调它:
public static List<T> GetAllDerivedTypes<T>(this Assembly assembly)
{
// …
List<object> types = new List<object>();
foreach (var definedType in assembly.DefinedTypes)
{
// …
types.Add(definedType);
}
return types.Cast<T>().ToList();
}
每次迭代中的 definedType
是Type
,类型为Type
的实例。因此,当您将其添加到types
列表时,您要添加类型。
然而,类型与具有泛型类型T
(您的接口)类型的对象不同。因此types.Cast<T>()
将失败,因为Type
无法转换为您的接口类型T
。同样,List<T>
的返回值没有意义,因为您返回了 types 的列表,而不是具有接口类型的对象列表。
所以你想把它改成这个:
public static List<Type> GetAllDerivedTypes<T>(this Assembly assembly)
{
// …
List<Type> types = new List<Type>();
foreach (var definedType in assembly.DefinedTypes)
{
// …
types.Add(definedType);
}
return types;
}
答案 2 :(得分:-1)
所以我做错了两件事。
IsAssignableFrom
Cast<T>
解决方案:
public static List<T> GetAllDerivedTypes<T>(this Assembly assembly)
{
var type = typeof(T);
var isInterface = type.IsInterface;
if (!isInterface)
{
throw new Exception("Not an interface type");
}
return assembly
.DefinedTypes
.Where(x => type.IsAssignableFrom(x) && !x.IsInterface)
.Select(Activator.CreateInstance)
.Cast<T>()
.ToList();
}