2

我正在建造一个简单的“公共汽车”作为概念证明。我不需要任何复杂的东西,但想知道如何最好地优化以下代码。我使用 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
    }
}
4

2 回答 2

5

这个怎么样(仅显示更改的部分):-

// 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);
    }
}

这里的关键是使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);
    }
}

- 更新 -

正如 Peter Lillevold 所指出的,您还应该考虑将类型参数添加到您的 IOC 容器方法中,如下所示:-

// IoC wrapper
static class IoC {
    public static T Resolve<T>() {
        ...
    }
}

这将像这样简化您的来电者:-

// Bus implementation
class BusImpl : IBus {
    public void Publish<T>(T cmd) where T : ICommand {
        var handler = IoC.Resolve<IHandles<T>>();
        handler.Handle(cmd);
    }
}

这是您最初问题的一个侧面,但对于 IOC 界面来说似乎是一个明智的设计。

于 2011-10-15T13:56:40.447 回答
0

这行得通吗?您的 IoC 正在返回对象,请考虑返回 T,然后您不必像下面那样处理类型歧义。

public void Publish(ICommand cmd) {
    var cmdType = cmd.GetType();
    var handler = IoC.Resolve(typeof(IHandles<>).MakeGenericType(cmdType)) as IHandles<ICommand>;
    if (handler != null)
    {
        // BEGIN SLOW
        handler.Handle(command);
        // END SLOW
    }
    //else throw some exception
}
于 2011-10-15T13:14:39.277 回答