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

本文关键字:实现 运行时 检测 接口 | 更新日期: 2023-09-27 18:13:36

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

我想在运行时进行检测,这样我就有能力在将来扩展接口的实现。

为了实现这一目标,我有哪些选择/方法?

例如

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;}
}

感谢尼古拉斯

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

您可以这样做:

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容器

使用反射可以相对容易地做到这一点,例如:

        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. 如何处理构造函数异常?

我建议看看依赖注入/控制反转容器,如Castle Windsor以及自动注册,例如:

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

有不同的选项来指定要扫描的程序集,如果你使用安装程序,你可以使你的系统非常可扩展。

我可以看到您如何使用反射来做到这一点-从程序集到它的类,然后询问每个类,看看它是否可以被强制转换为I - whatever -当然,这种方法虽然不是c#特定的,但肯定是。net特定的。

对你有用吗?

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

好的一致性实现可以像这样:

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

,你可以在以下的可接受答案中找到:获取实现接口的所有类型

这自然是只查看当前域的一个类型。