我正在尝试搜索特定的命名空间并返回实现指定接口并具有指定基类的所有类的实例。
这是代码
private List<T> GetInstancesWithInterface<T, T2>(string @namespace)
{
var tList = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace == @namespace)
.Where(t => t.BaseType == (typeof (T)) && t.GetInterfaces().Contains(typeof(T2)))
.Select(t => (T)Activator.CreateInstance(typeof(T), this))
.ToList();
return tList;
}
这是调用代码
var examples = GetInstancesWithInterface<DrawableGameComponent, IResettable>("GamePhysics.Physics");
foreach (var example in examples)
{
Debug.Assert(example is IResettable);
var r = example as IResettable;
_examples.Add(r);
Components.Add(example);
if (Components.Count == 0) continue;
example.Enabled = false;
example.Visible = false;
}
我遇到的问题是Assert失败,因为我找回了DrawableGameComponent
的列表,不能将其视为IResettable
,因此代码var r = example as IResettable
始终返回null。
其他信息
我还应该提到DrawableGameComponent
没有实现IResettable
接口。我尝试获取的三个示例类都有DrawableGameComponent
作为基类,它们还实现了IResettable
。
其他想法
我想也许我应该创建一个名为Example
的新抽象类来实现DrawableGameComponent
和IResettable
然后我的具体示例类可以实现Example
基础类。我想这个可能是更好的设计,但我也有兴趣知道我是否可以按原样运行它。
答案 0 :(得分:4)
您将错误的类型传递给Activator.CreateInstance
,您应将其更改为:
.Select(t => (T)Activator.CreateInstance(t, this))
您可能还想在Where
子句中使用Type.IsSubclassOf
,而不是直接查看基类。
答案 1 :(得分:3)
(根据评论要求发帖。感谢等待)
查看LINQ查询的Select
部分:
.Select(t => (T)Activator.CreateInstance(typeof(T), this))
将typeof(T)
传递到Activator.CreateInstance
会创建一个T
类型的新对象。由于您实际上想要从找到的类型中创建对象,因此您需要将其更改为:
.Select(t => (T)Activator.CreateInstance(t, this))
这将确保Activator创建上一个Where
中找到的类型的实例。
Lee还提到,在搜索子类时,在IsSubclassOf
表达式中使用IsAssignableFrom
或Where
等内容比直接==
更可取。根据我的经验,他们的工作方式基本相同,除了IsAssignableFrom
也适用于接口。