Как я могу избавиться от отражения отражения в этом куске кода? - PullRequest
2 голосов
/ 15 октября 2011

Я строю простой «автобус» в качестве доказательства концепции.Мне не нужно ничего сложного, но мне интересно, как лучше оптимизировать следующий фрагмент кода.Я использую 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
    }
}

Ответы [ 2 ]

5 голосов
/ 15 октября 2011

Как насчет этого (показаны только измененные детали): -

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

- ОБНОВЛЕНИЕ -

Как указал Питер Лиллевольд, вам также следует подумать о добавлении параметра типа в метод контейнера 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.

0 голосов
/ 15 октября 2011

Это работает?Ваш 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
}
...