简体   繁体   English

具有泛型的Unity配置

[英]Unity Configuration With Generics

I am currently in the process of designing a new message translation system at work and have the following question concerning DI and Unity. 我目前正在设计一个工作中的新消息翻译系统,并且对DI和Unity有以下问题。

I have the following interface: 我有以下界面:

public interface ITranslate<TInput, TOutput>
{
    TOutput TranslateMessage(TInput message);
}

With a concrete implementation of below (where InternalMessage is a custom class I have developed) 通过下面的具体实现(其中InternalMessage是我开发的自定义类)

public class TestTranslate : ITranslate<byte[], InternalMessage>
{
    InternalMessage Translate(byte[] message)
    {
        // Do the translation here and return the result....
    }
}

However I want to using unity inject a translator instance into my Translator service through the constructor. 但是我想使用unity通过构造函数将翻译器实例注入到我的翻译器服务中。 To be used in a method within the service. 在服务内的方法中使用。

public class TranslatorService
{    
    private readonly ITranslator translator;
    public TranslatorService(ITranslate translator)
    {
        this.translator = translator;
    }

    public byte[] DoTranslate(string message)
    {
        return translator.TranslateMessage(message);
    }
}

However I have 2 questions: 但是我有两个问题:

1) Is it possible to have the ITranslate in the constructor without specifiying the types that the translator will deal with (I am trying to keep the Service and Translator as generic as possible, so if another translation was needed I would only need to swap out the Concrete implementation of the Translator interface). 1)是否可以在构造函数中使用ITranslate而不指定转换程序将要处理的类型(我试图使Service和Translator尽可能通用,所以如果需要其他转换,我只需要换出转换器接口的具体实现)。

2) If this is possible how would I do it and then what would I have in my unity configuration to do that. 2)如果可能的话,我该怎么做,然后在统一配置中要做什么。 Note I am using the XML configuration (not my choice) to configure my dependenciues etc. 注意我正在使用XML配置(不是我的选择)来配置我的依赖项等。

Thanks In Advance 提前致谢

Stuart 斯图尔特

After some thinking, I assume you want to do the following: 经过一番思考,我假设您想执行以下操作:

  1. At some point, messages of different types come in and have to be 在某些时候,必须输入不同类型的消息
    translated to other types, somehow. 某种程度上翻译为其他类型。
  2. The component/client that receives these messages is and should be unaware of how different types of messages should be translated. 接收到这些消息的组件/客户端现在也应该不知道应如何翻译不同类型的消息。
  3. Therefore, you want to implement a generic TranslatorService-class that takes any message and magically translates is to the correct type, based on the input-message. 因此,您想实现一个通用的TranslatorService类,该类接受任何消息并根据输入消息神奇地将其转换为正确的类型。
  4. For each specific translation, you want to define a specific, generic Translator-class that is automatically instantiated and used by the TranslatorService-class, preferrably using dependency injection of some sort. 对于每个特定的转换,您都想定义一个特定的,通用的Translator-class,该类将由TranslatorService-class自动实例化并使用,最好使用某种依赖注入。

If my assumptions are correct, I would advise the following design. 如果我的假设是正确的,我会建议以下设计。

First of all, define a generic interface that must be implemented by each specialized Translator-class. 首先,定义必须由每个专门的Translator-class实现的通用接口。 Only make the input-type generic: 仅使输入类型通用:

interface IMessageTranslator<TMessage>
{
    object Translate(TMessage message);
}

Then create the TranslatorService such that clients can just push in arbitrary messages and gives them back the result, if and only if a Translator for that message exists: 然后创建TranslatorService,以使客户端仅在存在该消息的Translator的情况下,才可以推送任意消息并将其返回给他们:

class TranslatorService
{
    object Translate(object message)
    {

    }
}

Now the TranslatorService has to instantiate the correct IMessageTranslator<T> based on the type of message. 现在,TranslatorService必须根据消息的类型实例化正确的IMessageTranslator<T> You can do this with Unity by having the TranslatorService-class encapsulate a container that contains all IMessageTranslator<T> -types that you have implemented and then simply instantiate one based on the message type: 您可以通过使用TranslatorService类封装一个容器来实现这一目的,该容器包含已实现的所有IMessageTranslator<T> -types,然后根据消息类型简单地实例化一个:

class TranslatorService
{
    private readonly IUnityContainer _container;

    public TranslatorService()
    {
        _container = new UnityContainer();
        _container.RegisterType(typeof(IMessageTranslator<A>), typeof(MessageTranslatorA));
        _container.RegisterType(typeof(IMessageTranslator<B>), typeof(MessageTranslatorB));
        // Etc...
    }

    object Translate(object message)
    {
        if (message == null)
        {
           throw new ArgumentNullException("message");
        }
        var genericTranslatorDefinition = typeof(IMessageTranslator<>);
        var translatorType = genericTranslatorDefinition.MakeGenericType(message.GetType());
        var translator = _container.Resolve(translatorType);
        var translateMethod = translatorType.GetMethod("Translate", new [] { message.GetType() });

        return translateMethod.Invoke(translator, new object[] { message });
    }
}

Note that this is a naive implementation as to whether a translator actually exists/is registered for the specified message, and also in the way it finds the Translate-method (better to get it through the InterfaceMap), but you get the idea. 请注意,这是一个天真的实现,它涉及某个翻译器是否确实存在/是否已为指定的消息注册,并且还以其找到翻译方法的方式(最好通过InterfaceMap来获取),但是您可以理解。

If you want even more flexibility, you could create a mechanism that auto-fills your container by scanning the assembly for IMessageTranslator-implementors. 如果需要更大的灵活性,可以创建一种机制,通过扫描程序集的IMessageTranslator-implementor来自动填充容器。 That way, you just add a new implementation and you're ready to go. 这样,您只需添加一个新的实现,就可以开始使用了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM