开发者

how to properly decouple implementation specifics into class libraries in .net

开发者 https://www.devze.com 2023-03-24 18:59 出处:网络
I\'m wondering if there is a standard way in c#(or maybe even cli) to efficiently decouple implementation logic into separate class libraries/assemblies that would be dynamically loaded by a process t

I'm wondering if there is a standard way in c#(or maybe even cli) to efficiently decouple implementation logic into separate class libraries/assemblies that would be dynamically loaded by a process that will preforms actions on those libraries based on a common interface.

More precisely: Say I'm building a service that receives messages, and delegates handling of these messages to something else. Something like:

while(true){
   message = read_message_from_somewhere();
   class_from_another_lib.do_somthing_with_Message(message); 
}

I want the process to load a class lib in runtime from some sort of config. The lib, I assume, would have some main class or class factory that implements so开发者_JAVA百科me interface part of which looks like this:

ISomePublicIface{
   void do_somthing_with_Message(messageT);
}

This all feels somewhat java beenish where all I would need to do is have the a class in an assembly implement some sort of injectable interface add a line to the app config and get abunch of stuff for free.


Take a look at the Managed Extensibility Framework (MEF), which is included in .NET 4.0. MEF can dynamically load and inject components from external DLLs.


If you fancy a NIH solution... I've written up a slightly verbose version of this problem which allows you to use a DI container to store handlers for the message and dispatch to the relevant handler based on message. I've used autofac for the container here, but anything should be suitable as long as it can resolve open generics:

// Message marker interface
interface IMessage {}

// Message handler interface
interface IHandles<T> where T: IMessage
{
    void Handle(T message);
}

// A message which defines mooing
class MooMessage : IMessage {}

// A message which defines woofing
class WoofMessage : IMessage {}

// A handler for moo messages
class MooHandler : IHandles<MooMessage>
{
    public void Handle(MooMessage message)
    {
        Console.WriteLine("moo");
    }
}

// A handler for woof messages
class WoofHandler : IHandles<WoofMessage>
{
    public void Handle(WoofMessage message)
    {
        Console.WriteLine("woof");
    }
}

class Program
{
    // Generate some test messages
    static IEnumerable<IMessage> MessageGenerator()
    {
        yield return new WoofMessage();
        yield return new MooMessage();
    }

    static void Main(string[] args)
    {
        // configure container
        var builder = new ContainerBuilder();
        // Register message handlers here through configuration or convention...
        builder.RegisterType<WoofHandler>().AsImplementedInterfaces();
        builder.RegisterType<MooHandler>().AsImplementedInterfaces();
        var container = builder.Build();

        // handle all messages until done
        foreach (var message in MessageGenerator())
        {
            // resolve the handler for the message from the container
            var handler = container
                .Resolve(typeof(IHandles<>)
                .MakeGenericType(message.GetType()));

            // call the handler - you have to do this using reflection unfortunately
            // due to the nature of open generics.
            handler
                .GetType()
                .GetMethod("Handle")
                .Invoke(handler, new object[] { message });
        }
    }
}

You will obviously want to extract the concerns out a little from Main but it should give you the gist of the problem and solution.

0

精彩评论

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