2014-10-23 3 views
3

Command<CommandResult>을 인수로 사용하는 ExecCommand 메서드가 있습니다. 그러나 내가 CommandResult 유도 된 제네릭 형식으로 명령을 전달하려고 할 때 빌드 실패제네릭 형식을 캐스팅 할 때 오류가 발생했습니다.

class Program 
{ 
    class CommandResult 
    { 
    } 

    class Command<TResult> where TResult : CommandResult, new() 
    { 
     internal virtual TResult ParseReply(object reply) 
     { 
      return new TResult(); 
     } 
     public Action<TResult> CommandCompleteCallback = null; 
    } 

    class CommandA : Command<CommandResult> 
    { 
    } 

    class CommandResultForB : CommandResult 
    { 
    } 

    class CommandB : Command<CommandResultForB> 
    { 
     internal override CommandResultForB ParseReply(object reply) 
     { 
      return new CommandResultForB(); 
     } 
    } 

    static Queue<Command<CommandResult>> commandQueue = new Queue<Command<CommandResult>>(); 

    static void ThreadLoop() 
    { 
     // This threadloop transmits the first command on the queue to external library when executeNextCommand is set (it's using Peek, so the command stays in the queue until the external library calls OnCommandCompleteResponse() 
    } 
    static void OnCommandCompleteRespose(object reply) 
    { 
     // called from external library when command is complete 
     lock (commandQueue) 
     { 
      var command = commandQueue.Dequeue(); 
      if (command.CommandCompleteCallback != null) 
       command.CommandCompleteCallback(command.ParseReply(reply)); 
     } 
    } 
    static void ExecCommand(Command<CommandResult> command) 
    { 
     lock (commandQueue) 
     { 
      commandQueue.Enqueue(command); 
      if (commandQueue.Count == 1) 
       executeNextCommand.Set(); 
     } 
    } 

    static void Main(string[] args) 
    { 
     ExecCommand(new CommandA()); 
     ExecCommand(new CommandB()); // <-- this is the offending line 
    } 
} 

어떤 아이디어를 내가 'CommandB에서 명령으로 변환 할 수 없습니다'오류를 얻을 이유는 무엇입니까? CommandResultForB을 기본 클래스 CommandResult에 자동으로 캐스팅 할 수없는 이유는 무엇입니까? 당신이 CommandB 유형의 인스턴스로 ExecuteCommand()를 호출하고 여전히 가능한 한 일반적인 싶은 경우

+0

제네릭이 아닌 C++ 템플릿이기 때문에. – helb

답변

3

이 예외의 이유는 기본적으로 일반적인 매개 변수는 점이다 하지covariant :

이에 대한 지원은 .NET 3.5에서 추가되었다,하지만 당신은 인터페이스와 out 키워드를 통해 정의해야합니다 :

static void ExecCommand(ICommand<CommandResult> command){} 
:

interface ICommand<out TResult> where TResult : CommandResult, new() 
{ 
    TResult ParseReply(object reply); 
} 


class Command<TResult> : ICommand<TResult> where TResult 
         : CommandResult, new() 
{} 

은 그럼 당신은 인터페이스를 기대하는 당신의 execCommand 방법을 업데이트 할 수 있습니다

그 발견을 작동됩니다 ExecCommand 통화를 할 일단 :

static void Main(string[] args) 
{ 
    ExecCommand(new CommandA()); 
    ExecCommand(new CommandB()); // <-- works now   
} 
1

다음이를 사용

static void ExecCommand<TResult>(Command<TResult> command) 
    where TResult : CommandResult, new() 
{ 
    TResult res = command.ParseReply(null); 
} 

참고 : 이것은 원래의 질문에 대한 답변입니다. 문제의 일부분을 이해하는 데 도움이 될 수 있으며 다른 사람을 도울 수 있습니다.

+0

이것은 오류를 ExecCommand 내부로 옮기는 것입니다. 거기에 나는'Queue >'에 명령을 대기 시켜서 같은 오류가 발생합니다. –

+0

글쎄, 거기에 같은 문제가 있습니다. CommandResult에 결과를 캐스팅하면됩니다. 나는 그것에 대한 편집을 게시 할 것이다. – helb

+0

명령이 일반 콜백 매개 변수를 가지고 있기 때문에 너무 나쁘습니다. 올바른 형식 대신 인수로 CommandResult를 얻습니다. –

관련 문제