2011-10-15 2 views
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 
    } 
} 

답변

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); 
    } 
} 
여기서 핵심은 당신의 유형 유형 참조 T를 얻을 수 있음을 의미하는 제네릭 Publish 방법을 확인하는 것입니다

명령을 사용하여 캐스트를 만들 수 있습니다. 형식 매개 변수 제약 조건은 이전처럼 ICommand 만 전달할 수 있도록합니다. UPDATE - -

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

-

으로는 피터 Lillevold 지적, 당신은 또한 추가하는 방법에 대해 생각해야합니다 : -

가 BTW 나는이 테스트를했는데 작동, 여기에 전체 코드입니다 당신의 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

지금 일반 제약 조건 추가 및 테스트 - 답장을 보내 주셔서 감사합니다. 성공과 함께 게시됩니다 (희망 사항). – Deleted

+0

우수 - 정말 고마워요. 완벽하게 작동합니다! 제약 조건이 런타임이나 컴파일러를 손상시키지 않고 강제로 유형을 허용하는 방법을 알 수 있습니다. 좋은 해결책. 다시 한번 감사드립니다. – Deleted

+0

흠 ... 여기 뭔가가 빠졌습니까? 왜 그냥'var handler = IoC.Resolve >();'? 당신은 이미'T' 타입을 알고 있습니다 ... 제네릭 타입을 동적으로 만들 필요가 없습니다 ... –

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 
} 
+0

아니요 - null 체크 블록에있는 항목을 절대로 실행하지 않습니다. Resolve는 예외를 throw하지 않고 캐스트 할 수없는 Object를 반환합니다. 그것이 내가 시작한 곳입니다. 그것은 implable-up을 호출 할 수 없기 때문에 impl을 호출 할 수 없기 때문에 반사 혼란입니다. 실제로 강제 캐스트하면 유효하지 않은 캐스트 예외가 발생합니다.이 경우에는 "ConcreteHandlerImpl"유형을 "IHandles'1 [ICommand]"유형으로 변환 할 수 없습니다. 당신이 공분산/반항에 어떻게 든 할 수 있는지 확실하지 않습니다. – Deleted

+0

@Chris Smith : ConcreteHandlerImpl은 어떻게 생겼습니까? –

+0

무슨 일이 일어나고 있는지보기 힘들다면 IoC가 아마도 인터페이스를 사용하지 않는 유형이 될 것입니다. – CRice

관련 문제