如何从IoC容器中返回正确的类?

时间:2018-03-10 21:24:00

标签: c# inversion-of-control

我在C#中列出了以下接口:

public interface ICommand {}

public interface ICommandDispatcher<TCommand> where TCommand : ICommand {
void Dispatch(TCommand command);
}

public interface ICommandDispatcherFactory<TDispatcher, TCommand> 
where TDispatcher : ICommandDispatcher<TCommand>, new()
where TCommand : ICommand
{
    TDispatcher Create();
}

到目前为止,这么好。我可以创建我支持的命令并实现他们各自的调度员和工厂:

// Commands
public class CommandFileBase : ICommand
{
    private readonly string _filepath;

    public CommandFileBase(string filepath) {
        _filepath = filepath;
    }
}

public class CommandBackupFile : CommandFileBase
{
    public CommandBackupFile(string filepath) : base(filepath){}
}

public class CommandCreateFile : CommandFileBase
{
    public CommandCreateFile(string filepath) : base(filepath){}
}

public class CommandDeleteFile : CommandFileBase
{
    public CommandDeleteFile(string filepath) : base(filepath){}
}

// Dispatchers
public class CommandBackupFileDispatcher : ICommandDispatcher<CommandBackupFile>
{
    public void Dispatch(CommandBackupFile command)
    {
        //work
    }
}

public class CommandCreateFileDispatcher : ICommandDispatcher<CommandCreateFile>
{
    public void Dispatch(CommandCreateFile command)
    {
        //work
    }
}

public class CommandDeleteFileDispatcher : ICommandDispatcher<CommandDeleteFile>
{
    public void Dispatch(CommandDeleteFile command)
    {
        //work
    }
}

// Factories
public class CommandBackupFileDispatcherFactory 
: ICommandDispatcherFactory<CommandBackupFileDispatcher, CommandBackupFile>
{
    public CommandBackupFileDispatcher Create()
    {
        return new CommandBackupFileDispatcher();
    }
}

public class CommandCreateFileDispatcherFactory 
: ICommandDispatcherFactory<CommandCreateFileDispatcher, CommandCreateFile>
{
    public CommandCreateFileDispatcher Create()
    {
        return new CommandCreateFileDispatcher();
    }
}

public class CommandDeleteFileDispatcherFactory 
: ICommandDispatcherFactory<CommandDeleteFileDispatcher, CommandDeleteFile>
{
    public CommandDeleteFileDispatcher Create()
    {
        return new CommandDeleteFileDispatcher();
    }
}

现在,我想创建一个&#34;容器&#34;将每个支持的命令映射到其各自的调度程序工厂并包装Dispatch调用。我想映射工厂,因为一些调度员可能会将几个命令组合在一起。例如,可能有CommandBackupAndDeleteFile命令。所以我设计了这个ICommandContainer接口:

public interface ICommandContainer<TCommand> where TCommand : ICommand {
   void Dispatch(TCommand command);
}

我的问题在实现容器类时开始。我想要一个将ICommand类型映射到其调度程序工厂的字典,但我无法正确获取代码。我不确定我是否只是缺少某些东西,我的界面设计有缺陷,或者我是否完全错误。我已经尝试过类型,类型和字典类型的字典,对象和我似乎无法获得可以执行Dispatch()方法的返回对象。我也尝试使用工厂界面作为字典值,但当然是 编译器不喜欢那样。在我发现的其他容器实现中,激活器调用被转换为对象实现的接口。我不确定在我的情况下是否可行,因为我只能使用通用的Dispatcher类型。

public class CommandContainer<TDispatcher, TCommand>  : IContainer
where TDispatcher : ICommandDispatcher<TCommand>, new()
where TCommand : ICommand
{
    private readonly Dictionary<Type, object> _container;

    public CommandContainer()
    {
        _container = new Dictionary<Type, object>();
        _container.Add(typeof(CommandBackupFile), new CommandBackupFileDispatcherFactory());
        _container.Add(typeof(CommandCreateFile), new CommandCreateFileDispatcherFactory());
        _container.Add(typeof(CommandDeleteFile), new CommandDeleteFileDispatcherFactory());
    }

    public void Dispatch(TCommand command)
    {
        Type type = null;
        if (_dictionary.TryGetValue(typeof(TCommand), out type))
        {
            var factory = Activator.CreateInstance(type); // as TDispatcher
            //var dispatcher = factory.Create();
            //dispatcher.dispatch(command);
        }
        else
        {
            throw new InvalidOperationException("unsupported command");
        }
    }
}

这是我通过将代码与此论坛上的另一个容器合并而尝试的实现。

public class TestContainer2
{
    Dictionary<Type, Func<object>> registrations = new Dictionary<Type, Func<object>>();

    public TestContainer2()
    {
        Register<CommandBackupFile, CommandBackupFileDispatcher>();
        Register<CommandCreateFile, CommandCreateFileDispatcher>();
        Register<CommandDeleteFile, CommandDeleteFileDispatcher>();
    }

    public void Register<TCommand, TDispatcher>()
    where TDispatcher : ICommandDispatcher<TCommand>, new()
    where TCommand : ICommand
    {
        registrations.Add(typeof(TCommand), () => GetInstance(typeof(TDispatcher)));
    }

    public object GetInstance(Type serviceType)
    {
        Func<object> creator;
        if (registrations.TryGetValue(serviceType, out creator)) return creator();
        else if (!serviceType.IsAbstract) return CreateInstance(serviceType);
        else throw new InvalidOperationException("No registration for " + serviceType);
    }

    private object CreateInstance(Type implementationType)
    {
        var ctor = implementationType.GetConstructors().Single();
        var parameterTypes = ctor.GetParameters().Select(p => p.ParameterType);
        var dependencies = parameterTypes.Select(t => GetInstance(t)).ToArray();
        return Activator.CreateInstance(implementationType, dependencies);
    }

    public void Dispatch<TCommand>(TCommand command)
    {
        var dispatcher = GetInstance(typeof(TCommand));
        //dispatcher.Dispatch(command);
    }
}

0 个答案:

没有答案