2013-08-20 3 views
2

대리자 목록 (여기에서는 "mCommandHandlers")을 유지 관리하고 싶습니다.일반 대리자 형식의 대리자 형식 및 공분산

public delegate void CommandHandler<TCommand>(TCommand command) where TCommand : ICommand; 
public delegate void ICommandHandler(ICommand command); 
Dictionary<Type, ICommandHandler> mCommandHandlers; 

가 나는 등의 정확히 어떤 종류의 알과 같은 컴파일시 장점에 대한 첫 번째 유형을 사용한다 : 그들은 일반적인 위임있어 이후로, 나는 실제로 나는 그런 목록을 유지 관리 할 수 ​​있도록 위임의 두 번째 유형을 정의 TCommand 나의 위임의 구현에 사용되는 :

RegisterHandler<ResourceCommand>((command) => 
{ 
     if (command != null) 
     { 
      ResourceManager.ResourceReceived(command.ResourceName, command.ResourceHash, command.ResourceData); 
     } 
}); 

내부 RegisterHandler, 이제 다음을 수행 싶습니다 :

public void RegisterHandler<TCommand>(CommandHandler<TCommand> handler) where TCommand : ICommand 
{ 
     mCommandHandlers.Add(typeof(TCommand), handler); 
} 

하지만 다음 전자를 얻을 수 rror 메시지 :

오류 3 인수 2 :에서 CommandHandler<TCommand>' 'ICommandHandler'

이 왜로 변환 할 수 없습니다? 컴파일러는 실제로 첫 번째 델리게이트 형식이 인수가 적어도 ICommand 유형이어야한다고 말하면서 델리게이트 인스턴스가 두 번째 델리게이트 형식의 서명을 준수하는지 확인합니다.

답변

2

컴파일러는 사실 처음 대리자 형식 유형 ICommand의의 적어도 대리자 인스턴스뿐만 아니라 입력 초 대표의 서명을 준수 함을 보장 할 수있는 인자를 요구하는 것을 볼 하는가?

여기에는 두 가지 문제가 있습니다.

첫째, 위임 분산은 또 다른 하나의 대리자 형식의 암시 적 참조 변환을 허용하지 않습니다 - 당신이 호환되는 기존의에서 새로운 대리자 인스턴스를 만들 수 있습니다.

둘째, 당신은 어떤ICommand을 받아 들일 것입니다 ICommandHandler 반면 ... 분산에게 라운드 CommandHandler<TCommand>는 명령의 특정 유형을 수락 할 잘못된 방법을 가지고있다.

그래서 우리는이 작업을 수행 할 수도있을 것 같군요 :

CommandHandler<FooCommand> fooHandler = HandleFoo; 
ICommandHandler generalHandler = new ICommandHandler(fooHandler); 

그런 다음 우리는 호출 할 수

generalHandler(new BarCommand()); 

은 ... 당신은 어떻게 HandleFoo 방법은 그 대처하는 기대? 이

은 특정 TCommand에 대한 CommandHandler<TCommand>-ICommandHandler에서 변환, 새로운 대표가 호출 될 때 때문에, 항상 유효 할 것이다입니다.샘플 코드 :

using System; 

delegate void CommandHandler<TCommand>(TCommand command) 
    where TCommand : ICommand; 
delegate void ICommandHandler(ICommand command); 

interface ICommand {} 

class Command : ICommand {} 

class Test 
{ 
    public static void Main() 
    { 
     ICommandHandler x = null; 
     CommandHandler<Command> y = new CommandHandler<Command>(x); 
    } 
} 

나는 당신이 단지에 사전을 변경 제안 : 당신이 특정 대리자를 호출 할 때 그런 다음 핸들러의 오른쪽 종류로 캐스팅해야합니다

Dictionary<Type, Delegate> mCommandHandlers; 

-하는 그 시점에서 타입 매개 변수 때문에 알 수 있다고 가정합니다. 또는 Jared의 답변에 따라 캐스트를 수행하는 프록시 처리기를 만들 수 있습니다.

+0

어떻게 공분산 아이디어가 잘못된 방식으로 바뀌 었는지 알 수 있습니다. :) 내 특정 대리인은 mCommandHandlers의 일부로 ICommand를 받아들이 기 위해 기다릴 수 없습니다. 그 점을 지적 해 주셔서 감사합니다! – user1610325

2

문제는 두 대리자 형식이 단순히 호환되지 않는다는 것입니다. 이 작업을 수행하려면 인수를 ICommandTCommand 사이에서 변환하는 간접 계층을 추가해야합니다.

public void RegisterHandler<TCommand>(CommandHandler<TCommand> handler) 
    where TCommand : ICommand 
{ 
    mCommandHandlers.Add(
    typeof(TCommand), 
    (command) => handler((TCommand)command); 
); 
} 
+0

감사합니다. 그런 종류의 간접 참조에 대해서도 생각했지만 실제로 컴파일러가 호환되지 않는 이유를 정확히 알고 싶습니다. 대리인은 공변수 여야하며 모든 코드는 공분산을 요구합니다. – user1610325

+0

@ user1610325 : 내 대답을보십시오. 그들은 당신이 시도하는 방식과 실제로 호환되지 않습니다. 그들은 * 다른 * 방법 라운드 호환됩니다. 인수에 관계없이 항상 새 대표를 통해 원래 대표를 호출하는 것이 올바른지 생각해보십시오. - 컴파일러는 항상 작동하는지 확인합니다. –

+0

@ user1610325 -'Func' 델리게이트는 출력물에 공변량이 있지만 인수에는 반항적입니다. 귀하의 대리인은 어쨌든 분산 주석을 가지고 있지 않습니다. – Lee