开发者

Interface and Implementation in Separate Assemblies Using Reflection

I have two assemblies; AssemblyWithInterface and AssemblyWithClass. In AssemblyWithInterface I have an interface called IDoSomething which is implemented by TheClass in AssemblyWithClass. (AssemblyWithClass references AssemblyWithInterface.)

In AssemblyWithInterface 开发者_如何学JAVAI want to create instances of the class from AssemblyWithClass using reflection:

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

The assembly loads fine and the instance is created as a TheConcreteClass.

However, I'm unable to cast theConcreteClass to its implementing interface. I get an InvalidCastException here:

var theConcreteClassInterfaced = (IDoSomething)theConcreteClass;

And

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

is False.

What am I missing? (The goal is to have a command pattern-styled ability to add commands implementing the IDoSomething to the AssemblyWithClass and be able to execute them in AssemblyWithInterface without changing code in the AssemblyWithInterface.)

Platform is .NET 3.5 (can't use dynamic).

Update: The background for this question (to explain why I'm not complying to DIP) is that I have a legacy ASP.NET-application contained in one large assembly. I want to create a plugin assembly which can call into various parts of the legacy assembly to perform montoring and some automated tasks. I don't want any additional dependencies (references to other assemblies) added to the legacy assembly. The idea is to implement a hook in the legacy assembly (a new special page and a IPlugInOperation), add a montoring page with a corresponding code behind. Have the code behind execute various IPlugInOperations (drawing an interface to allow the admin to specify parameters to use for executing code in the legacy assembly). The PlugIn Assembly must reference the legacy assembly and the legacy assembly uses reflection to list and allow the admin to excute the various implementations of IPlugInOperation contained in the PlugIn Assembly.


The interfaces should not care about implementations.

Refactor and move all logic to a third assembly.

Update:

Specification assembly

  • public interface ICommand
  • public interface ICommandFactory

Class assembly (references specification)

  • internal class CreateUserCommand : ICommand
  • public class CommandFactory : ICommandFactory

Application assembly (references both)

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

Update2

Most modern solutions uses an inversion of control container to take care of the mapping between interfaces and implementations.

The other solution is to have a small set of factories which is used to create implementations for specific interfaces. In this case I would also use factory method pattern to let aggregate roots be able to create child aggregates. For instance, the class Order would have a method called CreateOrderLine which would return a IOrderLine object.


You have a kind of circular reference here, which is definitely not ideal, but it should be possible to do what you're after. Take a look at AppDomain.AssemblyResolve. I suspect what's happening is that reflecting to instantiate the class is causing the system to load an extra copy of your original interface assembly, so that the interface type it's implementing is no longer the same type that you have statically referenced. By implementing AssemblyResolve, you can search the list of loaded assemblies using AppDomain.GetAssemblies, returning the one with a matching name.

Here is one possible implementation:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜