使用反射的单独程序集中的接口和实现

本文关键字:接口 实现 集中 程序集 反射的 单独 程序 | 更新日期: 2023-09-27 18:05:48

我有两个程序集;AssemblyWithInterfaceAssemblyWithClass。在AssemblyWithInterface中,我有一个名为IDoSomething的接口,由TheClassAssemblyWithClass中实现。(AssemblyWithClass引用AssemblyWithInterface .)

AssemblyWithInterface中,我想使用反射从AssemblyWithClass创建类的实例:

var theAssembly = Assembly.Load("Company.AssemblyWithClass, { FQN... }");
var theConcreteClass = theAssembly.CreateInstance("Company.AssemblyWithClass.TheClass");

程序集加载良好,实例被创建为TheConcreteClass

但是,我无法将theConcreteClass强制转换为它的实现接口。我在这里得到一个InvalidCastException:

var theConcreteClassInterfaced = (IDoSomething)theConcreteClass;

var isAssignable = typeof(IDoSomething).IsAssignableFrom(theConcreteClass.GetType();

是错误的。

我错过了什么?(目标是拥有命令模式样式的能力,将实现IDoSomething的命令添加到AssemblyWithClass中,并能够在AssemblyWithInterface中执行它们,而无需更改AssemblyWithInterface中的代码。)

平台是。net 3.5(不能使用动态)。

更新:这个问题的背景(解释为什么我不遵守DIP)是我有一个遗留的ASP。包含在一个大型程序集中的。net应用程序。我想创建一个插件程序集,它可以调用遗留程序集的各个部分来执行监视和一些自动化任务。我不希望在遗留程序集中添加任何额外的依赖项(对其他程序集的引用)。我们的想法是在遗留程序集中实现一个钩子(一个新的特殊页面和一个IPlugInOperation),在后面添加一个带有相应代码的监控页面。让后面的代码执行各种IPlugInOperations(绘制一个接口,允许管理员指定用于执行遗留程序集中代码的参数)。插件程序集必须引用旧程序集,旧程序集使用反射来列出并允许管理员执行插件程序集中包含的IPlugInOperation的各种实现。

使用反射的单独程序集中的接口和实现

接口不应该关心实现。

重构并将所有逻辑移动到第三个程序集。

更新:

规范装配

  • 公共接口命令
  • ICommandFactory

类程序集(引用规范)

  • 内部类CreateUserCommand: iccommand
  • 公共类CommandFactory: ICommandFactory

应用程序程序集(引用两者)

public class Program
{
    private ICommandFactory _commandFactory;
    public static void Main(string[] argv)
    {
        // this is the only line that is really dependent of a specific
        // implementation.
        _commandFactory = new TheSpecificImplementationAssembly.CommandFactory();
        ICommand command = _commandFactory.Create("CreateUser");
        command.Execute();
    }
}

更新2

大多数现代解决方案使用控制反转容器来处理接口和实现之间的映射。

另一个解决方案是有一个小的工厂集合,用于创建特定接口的实现。在这种情况下,我还将使用工厂方法模式让聚合根能够创建子聚合。例如,类Order将有一个名为CreateOrderLine的方法,该方法将返回一个IOrderLine对象。

这里有一种循环引用,这肯定不是理想的,但它应该可以实现您所追求的。看一下AppDomain.AssemblyResolve。我怀疑正在发生的事情是反射实例化类导致系统加载原始接口程序集的额外副本,因此它实现的接口类型不再是您静态引用的相同类型。通过实现AssemblyResolve,您可以使用AppDomain搜索已加载程序集的列表。GetAssemblies,返回名称匹配的那个。

这是一个可能的实现:

    private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        return AppDomain.CurrentDomain.GetAssemblies().
                     FirstOrDefault(assembly => assembly.FullName == args.Name);
    }