Выполнение приведения универсального интерфейса

У меня есть подпрограмма обработки команд, которая должна получить объект Processor из моего контейнера IOC и вызвать для него ProcessCommand, процессоры - это конкретный объект, реализующий общий интерфейс:

public interface ICommandProcessor<in T> where T : Command
{        
    Error ProcessCommand(T command);
}

у меня проблема в том, что когда я пытаюсь получить процессор, у меня есть только ссылка на объект команды через базовый класс (Command), поэтому я не знаю тип T (за исключением времени выполнения)

Я ввел второй неуниверсальный интерфейс

public interface ICommandProcessorGeneric
{

}

public interface ICommandProcessor<in T>:ICommandProcessorGeneric where T : Command
{        
    Error ProcessCommand(T command);
}

и может извлечь процессор из контейнера IOC следующим образом:

 protected virtual CommandProcessingResult RecognizeAndProcessCommand<T>(T command) where T : Command
 {
    ICommandProcessor<T> commandProcessor;

    try
    {
        Debug.WriteLine(String.Format( "---- Looking for processor for type {0}", command.GetType().Name));
        var g = ServiceLocator.GetInstance<ICommandProcessorGeneric>(command.GetType().Name);                
        commandProcessor = g as ICommandProcessor<T>;  //returns null!!
        Debug.WriteLine(String.Format("---- Got Processor {0}", g.GetType().Name));
    }
    catch (Exception ex)
    {
        //handle the exception
    }
    return commandProcessor.ProcessCommand(command);
}

проблема в том, что commandProcessor в этом случае имеет значение null, так как T является Command, тогда как во время выполнения я знаю, что T является производным типом. объект g, возвращаемый из контейнера IOC, является правильной формой процесса, однако я не могу понять, как я могу привести g к типу, который позволит мне получить доступ к методу ProcessCommand.

Я также должен отметить, что вызов этого метода не может определить тип команды во время компиляции, поскольку команда извлекается из базы данных только по полю at ID и десериализуется.

1 ответ

Решение

Я написал сообщение в блоге по этой самой проблеме.

Итак, в основном то, что я делал в прошлом, - это создание абстрактного базового класса для вашего командного процессора вместе с общим:

public abstract class CommandProcessor
{
    public abstract Error ProcessCommand(Command command);
}

public abstract class CommandProcessor<TCommand> where TCommand : Command
{
    public override Error ProcessCommand(Command command)
    {
        if (command is TCommand == false)
            throw new ArgumentException("command should be of type TCommand");

        var cast = (TCommand)command;

        return this.ProcessCommand(cast);
    }

    public abstract Error ProcessCommand(TCommand command);
}

Теперь вам не нужно делать ничего особенного в зависимости от того, какой тип команды вы используете:

protected virtual CommandProcessingResult RecogniseAndProccessCommand<T>
    (T command) where T : Command
{
    var commandProcessor = (CommandProcessor)ServiceLocator.GetInstance<ICommandProcessorGeneric>(typeof(T).Name);

    return commandProcessor.ProcessCommand(command);
}
Другие вопросы по тегам