1

我有一个项目,它有命令和命令执行器类,它们接受给定的命令并做一些事情。

我使用结构映射和泛型来为我想在我的系统中运行的任何给定命令查找和创建执行器的实例。

例如:

我有一个基本执行程序类

public abstract class BaseExecutor<T> : IExecutor<T>
{
//do something
}

这是一个执行器的示例,它应该由结构映射为以下命令类创建:MyFakeCommand

public class MyFakeCommandExecutor : BaseExecutor<MyFakeCommand>
{
    public void Run(MyFakeCommand cmd)
    {
        //do something
    }
}

要将执行程序连接到命令,请通过调用 ConnectImplementationsToTypesClosing 配置结构映射。

public void RegisterExecutionAssembly<T>()
{
    IocContainer.Configure(c => c.Scan(scanner =>
    {
        scanner.AssemblyContainingType<T>();
        scanner.ConnectImplementationsToTypesClosing(typeof(IExecutor<>));
    }));
}

并找到给定命令的执行者,我调用以下命令

public IExecutor<T> GetExecutorFor<T>()
{
    return IocContainer.GetAllInstances<IExecutor<T>>().FirstOrDefault(); 
}

因此,要为命令运行执行程序,我可以执行以下操作:

var cmd = new MyFakeCommand();
var executor = GetExecutorFor(cmd);
executor.Run(cmd);

这一切都很好,直到我开始动态创建命令。

例如:

string commandTypeFullName = "Namespace.MyFakeCommand"
Type cmdType = Type.GetType(commandTypeFullName);

var cmd1 = JsonConvert.DeserializeObject(strCommand, cmdType);
var cmd2 = ObjectFactory.GetInstance(cmdType);

GetExecutorFor(cmd1); // fails to find executor
GetExecutorFor(cmd2); // fails to find executor

所以我的问题是如何配置结构映射以仍然找到动态实例化对象的执行器?

4

2 回答 2

1

You need to introduce a non-generic IExecutor interface that all of your IExecutor<T> implement.

Then you use the ObjectFactory.ForGenericType method. See https://github.com/structuremap/structuremap/blob/v2.6.3/Source/StructureMap/ObjectFactory.cs#L310

var executor = ObjectFactory.ForGenericType(typeof(IExecutor<>)).
  WithParameters(cmdType).
  GetInstanceAs<IExecutor>()

Now executor will be an instance of the non-generic IExecutor, which should also have a Run method. The executor implements the non-generic Run method by casting the command object and passing it to the generic Run method.

于 2013-04-15T14:31:09.303 回答
0

我不知道 StructureMap (我使用 SimpleInjector),但这个问题并不特定于容器,它是泛型的问题。

您通常可以使用 dynamic 关键字来实现您想要做的事情:

//slight tweak to your listed method so that it would work
public IExecutor<T> GetExecutorFor<T>(T instance)
{
    return IocContainer.GetAllInstances<IExecutor<T>>().FirstOrDefault(); 
}

测试代码:

string commandTypeFullName = "Namespace.MyFakeCommand"
Type cmdType = Type.GetType(commandTypeFullName);

dynamic cmd1 = JsonConvert.DeserializeObject(strCommand, cmdType);
dynamic cmd2 = ObjectFactory.GetInstance(cmdType);

dynamic exec1 = GetExecutorFor(cmd1);
dynamic exec2 = GetExecutorFor(cmd2);

最佳实践应该是限制动态的使用——它没有提供智能感知,没有编译时支持等。所以我会用这个来代替:

public void ExecuteCommand<T>(T command)
{
    IExecutor<T> executor = 
        IocContainer.GetAllInstances<IExecutor<T>>().FirstOrDefault(); 
    if (executor == null) throw new Exception();
    executor.Run(command)
}

测试代码:

string commandTypeFullName = "Namespace.MyFakeCommand"
Type cmdType = Type.GetType(commandTypeFullName);

dynamic cmd1 = JsonConvert.DeserializeObject(strCommand, cmdType);
dynamic cmd2 = ObjectFactory.GetInstance(cmdType);

ExecuteCommand(cmd1);
ExecuteCommand(cmd2);
于 2013-04-15T13:50:37.310 回答