简体   繁体   中英

How to create list of instances deriving from a base class that implements interface?

Consider the following interface and class declarations.

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> { }

Now I want to declare a list of processor instances like so, but cannot figure out what generic type will allow me to add any derived processor type to the list.

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

I have tried:

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

and

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

and

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

What should the type of this list be? I know I must be missing something obvious here. Any help here would be greatly appreciated. Thanks!

You need to introduce IMessageProcessor and inherit all your Processors from it. In list you would have to use this interface.

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 {
}

And Processors:

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

Since there is no inheritance relationship between ISomething<Type1> and ISomething<Type2> you can't have list of objects that contain mix of those types.

Only real option is to force some base type - either use List<object> or better have base non-generic interface for IMessageProcessor<T> like IMessageProcessor<T> : IMessageProcessor .

Unfortunately it also means you can't have access to properties/arguments using generic type without casts.

I'm not sure what you are trying to accomplish, but your code will indeed not work.

I did the following:

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

And then:

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

will work.

The problem is that

public class MessageAProcessor : MessageProcessorBase<MessageA> { }

is too specific, and you can't cast this back to MessageProcessorBase<MessageBase> in the List<> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM