Del*_*ted 2 c# reflection command autofac bus
我正在构建一个简单的"总线"作为概念证明.我不需要任何复杂的东西,但我想知道如何最好地优化下面的代码.我使用Autofac作为容器将命令解析为开放泛型,但实际执行命令当前是通过反射完成的,因为传入的命令无法转换为代码中的具体类型.查看代码 - 用// BEGIN // END标记 - 目前正在使用反射完成.有没有办法在不使用反射的情况下做到这一点?
// IoC wrapper
static class IoC {
public static object Resolve(Type t) {
// container gubbins - not relevant to rest of code.
}
}
// Handler interface
interface IHandles<T> {
void Handle(T command);
}
// Command interface
interface ICommand {
}
// Bus interface
interface IBus {
void Publish(ICommand cmd);
}
// Handler implementation
class ConcreteHandlerImpl : IHandles<HelloCommand> {
public void Handle(HelloCommand cmd) {
Console.WriteLine("Hello Command executed");
}
}
// Bus implementation
class BusImpl : IBus {
public void Publish(ICommand cmd) {
var cmdType = cmd.GetType();
var handler = IoC.Resolve(typeof(IHandles<>).MakeGenericType(cmdType));
// BEGIN SLOW
var method = handler.GetType().GetMethod("Handle", new [] { cmdType });
method.Invoke(handler, new[] { cmd });
// END SLOW
}
}
Run Code Online (Sandbox Code Playgroud)
怎么样(只显示更改的部分): -
// Handler interface
interface IHandles<T> where T : ICommand {
void Handle(T command);
}
// Bus interface
interface IBus {
void Publish<T>(T cmd) where T : ICommand;
}
// Bus implementation
class BusImpl : IBus {
public void Publish<T>(T cmd) where T : ICommand {
var handler = (IHandles<T>)IoC.Resolve(typeof(IHandles<T>));
handler.Handle(cmd);
}
}
Run Code Online (Sandbox Code Playgroud)
这里的关键是使Publish方法通用,这意味着您获得T命令类型的类型引用,然后可以使用它来进行转换.类型参数约束只是确保只能ICommand传递一个,如前所述.
顺便说一句 - 我已经测试了这个并且它有效,这里是完整的代码: -
public static void Main(){
new BusImpl().Publish(new HelloCommand());
}
// IoC wrapper
static class IoC {
public static object Resolve(Type t) {
return new ConcreteHandlerImpl();
}
}
// Handler interface
interface IHandles<T> where T : ICommand {
void Handle(T command);
}
// Command interface
interface ICommand {
}
// Handler implementation
class ConcreteHandlerImpl : IHandles<HelloCommand> {
public void Handle(HelloCommand cmd) {
Console.WriteLine("Hello Command executed");
}
}
public class HelloCommand:ICommand{}
// Bus interface
interface IBus {
void Publish<T>(T cmd) where T : ICommand;
}
// Bus implementation
class BusImpl : IBus {
public void Publish<T>(T cmd) where T : ICommand {
var handler = (IHandles<T>)IoC.Resolve(typeof(IHandles<T>));
handler.Handle(cmd);
}
}
Run Code Online (Sandbox Code Playgroud)
- 更新 -
正如Peter Lillevold所指出的,你还应该考虑在你的IOC容器方法中添加一个类型参数,如下所示:
// IoC wrapper
static class IoC {
public static T Resolve<T>() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
这将简化您的调用者,如下所示: -
// Bus implementation
class BusImpl : IBus {
public void Publish<T>(T cmd) where T : ICommand {
var handler = IoC.Resolve<IHandles<T>>();
handler.Handle(cmd);
}
}
Run Code Online (Sandbox Code Playgroud)
这是您原始问题的一个侧面点,但对于IOC界面来说似乎是一个明智的设计.