2016-03-04 85 views
4

假設我有以下代碼:似乎無法獲得通用協方差/逆變工作

public interface IBaseMessage { } 

public interface IMessageProcessor<in T> where T : IBaseMessage { 
      void Process(T msg); 
     } 

public class RRMessage : IBaseMessage { 
      //something here 
     } 

public class BaseMessageProcessor { 
     //something here 
     } 

public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessor<RRMessage> { 
      public void Process(RRMessage msg) { 
       Console.WriteLine("Processed RRMessage"); 
      } 
     } 

public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>(); 

[Test] 
public void Test1() { 
    var msgProcessor = new RRMessageProcessor(); 
    MessageProcessors.Add(typeof(RRMessage), msgProcessor); 
    } 

我啓用逆變爲接口IMessageProcessor。爲什麼MessageProcessors.Add(typeof(RRMessage), msgProcessor);原因編譯時錯誤:

Argument 2: cannot convert from 'RRMessageProcessor' to 'IMessageProcessor<IBaseMessage>'

現在看來似乎應該是能夠轉換,因爲RRMessageProcessor:IMessageProcessor<RRMessage:IBaseMessage>>我怎樣才能得到這個工作?

+0

'IMessageProcessor '是在'T'逆變所以你只能分配'IMessageProcessor '到'IMessageProcessor '對於某些亞型'RRMessage'的'TSub'。你想要的轉換將是不安全的,因爲它可以讓你在需要RRMessage參數時調用RRMessageProcessor.Process(new BaseMessage())。 – Lee

+0

你會如何改寫? – Denis

+0

@Denis最好你可以在這裏做的是讓你的詞典'Dictionary '。 – juharr

回答

2

IMessageProcessor<in T>是在T逆變,而不是協變。這意味着以下是可以的:

class RRSubtype : RRMessage {} 
IMessageProcessor<RRSubtype> p = new RRMessageProcessor(); 

你正在嘗試做的是靜態不安全,因爲它允許你做:

class NotRRMessage : IBaseMessage { } 
IMessageProcessor<IBaseMessage> p = new RRMessageProcessor(); 
p.Process(new NotRRMessage()); 

,所以你需要保持安全動態,這樣你們似乎試圖用字典Type -> Processor。因此,您可以創建一個不安全的包裝類型:

public class ProcessorWrapper<T> : IMessageProcessor<IBaseMessage> { 
    private readonly IMessageProcessor<T> inner; 
    public ProcessorWrapper(IMessageProcessor<T> inner) { this.inner = inner; } 

    public void Process(IBaseMessage msg) 
    { 
     if(msg is T) { inner.Process((T)msg); } 
     else throw new ArgumentException("Invalid message type"); 
    } 
} 

你可以接着用這些包裝構建您的列表,同時保持輸入的內部處理器,只要你想如

public Dictionary<Type, IMessageProcessor<IBaseMessage>> MessageProcessors = new Dictionary<Type, IMessageProcessor<IBaseMessage>>(); 
MessageProcessors.Add(new ProcessorWrapper<RRMessage>(new RRMessageProcessor()); 
+0

您能否請您說明如何在字典中使用ProcessorWrapper以及如何將RRMessageProcessor添加到該字典中。我試圖創建一個字典,但什麼? Dictionary >? – Denis

+0

@Denis - 查看更新。 – Lee

+0

完美,謝謝! – Denis

相關問題