4

コマンド パターンを実装する 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);

ヘルプ?

4

3 に答える 3

3

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)
    {
    }
  }

今すぐ動作する必要があります

于 2012-08-31T13:55:16.357 に答える
2

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);
于 2012-08-31T13:37:58.483 に答える
1

最良の可能性は、使用するインターフェースを提供し、CommandクラスAbstractCommandHandler<>にそのインターフェースを実装させることです。このようなもの:

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

なんで?Commandtoを渡すHandleCommandことだけが保証できるからです。設計時にコマンド タイプが不明な場合、パラメータ値をチェックすることはできません。したがって、コンパイラは に何もキャストできませんAbstractCommandHandler<>

つまり、型の実際の型引数を省略したからといって、型の引数Tが魔法のようになるわけではありません。Commandそれは単に未指定になります。また、はのサブクラスでAbstractCommandHandler<PostStatCommand>ないAbstractCommandHandler<>ため、その型の変数に割り当てることができないことに注意してください。

于 2012-08-31T13:44:25.590 に答える