I have a piece of code like this:
var senders = new List<MessageSenderBase<object>>();
senders.Add(new MessageSender1<MessageType1>());
where MessageSender1<MessageType1> is derived from MessageSenderBase<T> and MessageType1 is another class I defined.
Now the 2nd line has error which says CS1503 Argument 1: cannot convert from 'Demo.MessageSender.MessageSender1<Demo.MessageSender.MessageType1>' to 'Demo.MessageSender.MessageSenderBase<object>'
How can I solve this issue?
My design is that MessageSenderBase<T> will sit in my library, and at the API level the user can derive their own sender class and specify their own type of message they want to send. I thought this would work since object is the base class of MessageType1 and MessageSenderBase<> is the base class of MessageSender1<>.
Please help, thanks!
Edit - adding MessageSenderBase
public class MessageSender1<MessageType1> : MessageSenderBase<MessageType1>
{
public override string Topic => "topic1";
public async override Task SendAsync()
{
//...
}
}
public abstract class MessageSenderBase<T>
{
public abstract string Topic { get;}
public T Deserialize(string json)
{
return JsonConvert.DeserializeObject<T>(json);
}
public abstract Task SendAsync();
}
CodePudding user response:
One way to work around this is to add a new covariant interface that has the "shape" of MessageSenderBase<T>:
public interface IMessageSender<out T> {
string Topic { get; }
T Deserialize(string json);
Task SendAsync();
}
public abstract class MessageSenderBase<T>: IMessageSender<T>
{
public abstract string Topic { get;}
public T Deserialize(string json)
{
return JsonConvert.DeserializeObject<T>(json);
}
public abstract Task SendAsync();
}
If you now make your list to be of type List<IMessageSender<object>>, you can put AnyMessageSender<AnythingReferenceType> in it.
var senders = new List<IMessageSender<object>>();
senders.Add(new MessageSender1<MessageType1>());
Note that if MessageSenderBase has a method that takes a T as parameter (or more generally, has a T in an "input position"), you should not include that in IMessageSender, because if you did, it is not safe to convert from MessageSender1<MessageType1> to IMessageSender<object> anymore. Imagine if you had:
public interface IMessageSender<out T> {
...
void Foo(T someT); // suppose this is implemented in MessageSender1
}
And you would be able to do:
var senders = new List<IMessageSender<object>>();
senders.Add(new MessageSender1<MessageType1>());
senders[0].Foo("abc"); // let's try giving a string to Foo
But senders[0] is a MessageSender1<MessageType1> object. MessageSender1<MessageType1>.Foo only accepts MessageType1 objects, not string!
