2016-09-21 25 views
2

次のインターフェイスとクラスの宣言を考えてみましょう。インターフェイスを実装する基本クラスから派生したインスタンスのリストを作成する方法は?

public interface IMessage 
{ 
    string Body { get; set; } 
} 
public abstract class MessageBase : IMessage 
{ 
    public string Body { get; set; } 
} 
public class MessageA : MessageBase { } 
public class MessageB : MessageBase { } 
public class MessageC : MessageBase { } 

public interface IMessageProcessor<T> where T : IMessage 
{ 
    Action<T> ProcessorAction { get; set; } 
} 
public abstract class MessageProcessorBase<T> : IMessageProcessor<T> where T : MessageBase 
{ 
    public Action<T> ProcessorAction { get; set; } 
} 
public class MessageAProcessor : MessageProcessorBase<MessageA> { } 
public class MessageBProcessor : MessageProcessorBase<MessageB> { } 
public class MessageCProcessor : MessageProcessorBase<MessageC> { } 

は今、私はそうのようなプロセッサインスタンスのリストを宣言したいのですが、一般的なタイプは私がリストに任意の派生プロセッサタイプを追加することができますかを把握することはできません。

var processors = new List<???>(); 
processors.Add(new MessageAProcessor()); 
processors.Add(new MessageBProcessor()); 
processors.Add(new MessageCProcessor()); 

私が試してみました:

// compiles but throws InvalidCastException 
var processors = new List<IMessageProcessor<IMessage>>(); 
processors.Add((IMessageProcessor<IMessage>)new MessageAProcessor()); 

// compiles but throws InvalidCastException 
var processors = new List<IMessageProcessor<MessageBase>>(); 
processors.Add((IMessageProcessor<MessageBase>)new MessageAProcessor()); 

// won't compile 
var processors = new List<MessageProcessorBase<MessageBase>>(); 
processors.Add((MessageProcessorBase<MessageBase>)new MessageAProcessor()); 

をこのリストのタイプは何をすべきですか?私はここで明白な何かを見逃しているに違いないことを知っここのお手伝いが大変ありがとうございます。ありがとう!

答えて

3

IMessageProcessorを導入し、すべてのプロセッサを継承する必要があります。リストでは、このインタフェースを使用する必要があります。

public interface IMessage { 
    string Body { get; set; } 
} 

public abstract class MessageBase : IMessage { 
    public string Body { get; set; } 
} 

public class MessageA : MessageBase { 
} 

public class MessageB : MessageBase { 
} 

public class MessageC : MessageBase { 
} 

public interface IMessageProcessor<T> where T : IMessage { 
    Action<T> ProcessorAction { get; set; } 
} 

public abstract class MessageProcessorBase<T> : IMessageProcessor<T> where T : MessageBase { 
    public Action<T> ProcessorAction { get; set; } 

    public void ProcessMessage(IMessage message) { 
     var msg = message as T; 
     ProcessorAction(msg); 
    } 
} 

public interface IMessageProcessor { 
    void ProcessMessage(IMessage message); 
} 

public class MessageAProcessor : MessageProcessorBase<MessageA>,IMessageProcessor { 
} 

public class MessageBProcessor : MessageProcessorBase<MessageB>,IMessageProcessor { 
} 

public class MessageCProcessor : MessageProcessorBase<MessageC>,IMessageProcessor { 
} 

とプロセッサ:

var processors = new List<IMessageProcessor>(); 
processors.Add(new MessageAProcessor()); 
processors.Add(new MessageBProcessor()); 
processors.Add(new MessageCProcessor()); 
+0

'ProcessMessage'の実装を' var msg = message as T' –

+0

@AlekseyLに移動することができます。良い点、修正、ありがとう – 3615

+0

@ 3615ありがとう - 私はそれを見ることが明らかになったようです。 –

1

ISomething<Type1>との間には継承関係がないのでISomething<Type2>あなたはこれらの型の混在するオブジェクトのリストを持つことはできません。

List<object>以上を使用すると、IMessageProcessor<T> : IMessageProcessorのようなベース非ジェネリックインターフェイスがIMessageProcessor<T>のようになります。

残念ながら、キャストなしでジェネリック型を使用してプロパティ/引数にアクセスすることはできません。

0

あなたが達成しようとしていることはわかりませんが、あなたのコードは実際には動作しません。

私は次のことをやった:

public class MessageAProcessor : MessageProcessorBase<MessageBase> { } 
public class MessageBProcessor : MessageProcessorBase<MessageBase> { } 
public class MessageCProcessor : MessageProcessorBase<MessageBase> { } 

そして:

var processors = new List<MessageProcessorBase<MessageBase>>(); 
processors.Add(new MessageAProcessor()); 
processors.Add(new MessageBProcessor()); 
processors.Add(new MessageCProcessor()); 

が動作します。

問題が

public class MessageAProcessor : MessageProcessorBase<MessageA> { } 

があまりにも特異的であることである、とあなたはList<>MessageProcessorBase<MessageBase>にこの背中をキャストすることはできません。

関連する問題