Создать экземпляр Generic

c# generics

515 просмотра

3 ответа

5865 Репутация автора

У меня есть служба WCF, которая реализует шаблон команды. Используя рефлексию, я создал словарь, в котором ключ - это тип команды, а значение - CommandHandler. Идея состоит в том, чтобы получить команду из WCF, используя словарь для получения типа обработчика, а затем создать экземпляр обработчика с помощью активатора.

    public CommandResponse RunCommand(Command command)
    {
        _logger.Trace("Running Command");
        var handlerType = HandlerMap[command.GetType()];

        var handler = (AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

        handler.HandleCommand(command);
        return new PostStatCommandResponse();

    }

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

Проблема в том, что Activator.CreateInstance возвращает объект, а не строго типизированный обработчик команд. Мне нужно иметь возможность вызывать HandleCommand, но я не могу понять, как привести его к базовому AbstractCommandHandler <>

// Syntax error.  Gotta provide type to generic
(AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

// Casting error at run time
(AbstractCommandHandler<Command>)Activator.CreateInstance(handlerType);

// This is dumb and defeats the purpose.
(AbstractCommandHandler<PostStatCommand>)Activator.CreateInstance(handlerType);

Помогите?

Автор: Darthg8r Источник Размещён: 31.08.2012 01:22

Ответы (3)


2 плюса

80115 Репутация автора

Решение

Почему бы просто не позвонить HandleCommandчерез отражение?

var handler = Activator.CreateInstance(handlerType);
handlerType.GetMethod("HandleCommand").Invoke(handler, new [] {command});

Или создайте неуниверсальный базовый класс (интерфейс тоже подойдет):

public abstract class AbstractCommandHandler
{
    public abstract void HandleCommand(Command command);
}

public abstract class AbstractCommandHandler<T> : AbstractCommandHandler
{
    public override void HandleCommand(Command command)
    {
        HandleCommand((T) command);
    }

    public abstract void HandleCommand(T command);
}

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

и в вашем RunCommandметоде:

var handler = Activator.CreateInstance(handlerType);
((AbstractCommandHandler)handler).HandleCommand(command);
Автор: sloth Размещён: 31.08.2012 01:37

1 плюс

15745 Репутация автора

Наилучшей возможностью будет предоставить интерфейс, который будет использовать Commandваш AbstractCommandHandler<>класс для реализации этого интерфейса. Что-то вроде этого:

public interface ICommandHandler
{
    void HandleCommand(Command command);
}

Почему? Поскольку прохождение CommandTo HandleCommandединственное , что вы можете гарантировать. Если тип команды не известен во время разработки, значение параметра не может быть проверено по нему. Следовательно, компилятор не позволит вам ничего бросить AbstractCommandHandler<>.

Другими словами, аргумент типа Tне волшебным образом становится Commandпросто потому, что вы опускаете фактический аргумент типа для типа. Это будет просто не указано. Также обратите внимание, что AbstractCommandHandler<PostStatCommand>он не является подклассом AbstractCommandHandler<>и, следовательно, не может быть назначен переменной этого типа.

Автор: O. R. Mapper Размещён: 31.08.2012 01:44

3 плюса

5273 Репутация автора

То, что OR Mapper сказал об интерфейсах, которые я реализовывал, и он опередил меня, вы можете привести универсальный тип к этому и затем вызвать метод.

  Command c = new PostStatCommand();
  var genericType = typeof(AbstractCommandHandler<>).MakeGenericType(c.GetType());
  ICommandHandler handler = (ICommandHandler)Activator.CreateInstance(genericType);
  handler.HandleCommand(c);

Заставьте AbstractCommandHandler реализовать ICommandHandler

 public class AbstractCommandHandler<T> : ICommandHandler
  {
    public void HandleCommand(Command c)
    {
    }
  }

Должен работать сейчас

Автор: LukeHennerley Размещён: 31.08.2012 01:55
Вопросы из категории :
32x32