在运行时检测接口的所有具体实现

时间:2013-05-14 14:52:33

标签: c# oop

我正在尝试创建一些代码来检测c#中接口的所有具体实现。但是我不相信我面临的问题仅限于c#,这是一个普遍的oop问题。

我想在运行时进行检测,因此我可以在将来扩展接口的实现。

为实现这一目标,我可以使用哪些选项/方法?

例如

public interface IAnimal{
 void MakeNoise();
}
public class Dog : IAnimal{
  public void MakeNoise()
  {
    Console.WriteLine("WOOF");
  }
}
public class Cat : IAnimal{
  public void MakeNoise()
  {
    Console.WriteLine("Meow");
  }
}
public class AnimalInstanceController{
  /*Im trying to populate this with all classes that implement IAnimal 
  */   
  public IEnumerable<IAnimal> {get;set;}
}

由于

尼古拉斯

4 个答案:

答案 0 :(得分:4)

您可以执行以下操作:

var implementations = new List<Type>();
foreach (Assembly assembly in <collection of assemblies you want to scan>)
{
  foreach (Type type in assembly.GetTypes())
  {
    if (type.GetInterfaces().Contains(typeof(IAnimal)))
    {
      implementations.Add(type);
    }
  }
}

或使用像Autofac

这样的DI容器

答案 1 :(得分:1)

您可以使用反射相对轻松地完成此操作,例如:

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var allTypes = assemblies.SelectMany(x => x.GetTypes());
        var implTypes = allTypes.Where(t => !t.IsInterface && !t.IsAbstract)
                 .Where(t => typeof (IAnimal).IsAssignableFrom(t));
        var animals = implTypes.Select(t => (IAnimal) Activator.CreateInstance(t))
                               .ToArray();

然而,有许多问题:

  1. 如果构造函数中有任何依赖项,解析这些
  2. 会变得非常复杂
  3. 如何确定要探测的装配体?上面的示例仅探测已加载的程序集
  4. 你如何处理构造函数异常?
  5. 我建议查看控制容器的依赖注入/反转,例如Castle Windsor和自动注册,例如:

     container.Register(AllTypes.FromAssemblyContaining<IAnimal>().BasedOn<IAnimal>());
    

    有多种选项可以指定要扫描的程序集,如果使用安装程序,则可以使系统具有可扩展性。

答案 2 :(得分:0)

我可以看到你如何使用反射来实现这一点 - 从一个程序集到它的类,然后询问每一个以查看它是否可以转换为IWhatever - 但当然这种方法而不是c#-specific肯定是.net特异性。

对你有用吗?

答案 3 :(得分:0)

您可以使用具体类型实现的Type.IsAssignableFrom 信息 看它是否实现了一个接口(可以分配给它)。

良好的实施可以是这样的:

var type = typeof(IMyInteraface);
var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

您可以在接受的答案中找到:Getting all types that implement an interface

这自然只能看到当前域的类型。