.net 公共接口的逆变接口

zed5wv10  于 2023-02-26  发布在  .NET
关注(0)|答案(1)|浏览(155)

我有如下逆变接口及其实现

public interface IMessageSender<in TMessage>
{
    Task SendAsync(TMessage @object);
}

public class MessageSender<TMessage> : IMessageSender<TMessage>
{
    public Task SendAsync(TMessage @object)
    {
        throw new NotImplementedException();
    }
}

我有应该表示TMessage的类的层次结构。

public class Base { }
public class Descendant1 : Base { }
public class Descendant2 : Base { }

为简单起见,我有两个发送方

var descendant1Sender  = new MessageSender<Descendant1>();
var descendant2Sender  = new MessageSender<Descendant2>();

我如何将这两个发送方强制转换为公共接口,以传递给方法,例如。

static void SomeMethod( IServiceBusMessageSender<Base> baseSender)
{
    baseSender.SendAsync(new Descendant1());
}

SomeMethod(descendant1Sender);  //This won't compile because of contravariance
lb3vh1jj

lb3vh1jj1#

不能将IMessageSender<Descendant1>视为IMessageSender<Base>,因为它不是1,无论是否逆变,它要求参数是Descendant1Descendant1的后代。
Contravariance允许使用IMessageSender<Base>作为IMessageSender<Descendant1>,而不是相反。也就是说,下面的代码将起作用(如果您使接口不变,将导致编译错误):

IMessageSender<Base> baseSender = ...;
IMessageSender<Descendant1> descendantSender = baseSender;

Demo

统一采购司

作为解决方法,您可以考虑引入接口的非泛型版本和/或一些类型检查:

public interface IMessageSender
{
    Task SendAsync(Base @object);
    bool CanSend(Base msg);
}
public interface IMessageSender<in TMessage> : IMessageSender
{
    Task SendAsync(TMessage @object);
}

public class MessageSender<TMessage> : IMessageSender<TMessage>
{
    public bool CanSend(Base msg) => typeof(TMessage).IsAssignableFrom(msg.GetType());

    public Task SendAsync(TMessage @object) => Task.CompletedTask;

    async Task IMessageSender.SendAsync(Base @object) // explicit interface implementation
    {
        if(@object is TMessage msg)
        {
            await SendAsync(msg);
        }
        else 
        {
            throw new Exception(); // or ignore
        }
    }
}

其思想是SomeMethod将检查处理程序是否可以发送消息。

相关问题