c# - 通用列表的接口(interface)继承

标签 c# generics interface variance

我想为一个简单的项目构建一个生产者和消费者的通用系统。

我现在拥有的是

public interface IMessage     {    }
public interface Message1 : IMessage    {    }
public interface Message2 : IMessage    {    }
public interface IConsumer<T>    {    }
public interface IProducer<T>    {    }

public class Mop1 : IConsumer<Message1>, IProducer<Message2>
{
}



class Program
{
    static void Main(string[] args)
    {
        var list = new List<IConsumer<IMessage>>();
        var mop = new Mop1();
        list.Add(mop);   // Error occurs here
    }
}

最后一行给出类似 cannot convert from 'Mop1' to 'IConsumer<GenericPubSub.IMessage>' 的错误

但是 Mop1 实现了一个 IMessage 派生类型的 IConsumer。这是一些方差问题吗?这有什么问题?

最佳答案

这是一个棘手的案例。您可以使用协变/逆变,但是...

我会稍微简化代码。只是为了关闭编译器,你可以这样做:

public interface IMessage { }

public interface Message1 : IMessage { }


public class Mop1 : IConsumer<Message1>
{
}

public interface IConsumer<out IMessage>
{
}


class Program
{
    static void Main(string[] args)
    {
        var list = new List<IConsumer<IMessage>>();
        var mop = new Mop1();

        list.Add(mop);   // Error occurs here
    }
}

out IMessage将按照另一个答案中的建议进行操作,但它从根本上没有解决任何问题。让我展示一下,现在你想制作你的界面:

public interface IConsumer<out IMessage>
{
    object Process (IMessage m);
}

aaa 它不会编译。因为简单地说,如果你说 out IMessage这意味着返回类型应该从 IMessage 派生,而不是参数类型。

所以你会这样:

public interface IConsumer<in IMessage>
{
    object Process (IMessage m);
}

public class Mop1 : IConsumer<Message1>
{
    public object Process (Message1 msg)
    {
        return null;
    }
}

使其编译有效。但是现在你的 list.Add(mop);不管用。这是理所当然的,因为你的 Mop1确实不能转换为 IConsumer<IMessage>因为如果它是以下代码将是可能的:

list[0].Process (new Message2 ());

这是不可能的,因为 Mop1 只接受 Message1 .

所以回答这个问题。您实际上无法使用消息调度和纯 C# 编译器功能做任何有意义的事情。我知道它的发展方向,你想要静态类型的消息和东西。不幸的是,您不能拥有在通用列表中使用特定消息的消费者列表,您必须具有像 bool CanProcess(IMessage); IMessage Process(IMessage); 这样的抽象签名。并投在里面。您也可以使用自定义属性和反射稍微好一点,但同样,不能完全使用 C# 编译器。

关于c# - 通用列表的接口(interface)继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27510643/

相关文章:

具有动态函数参数的 C# 编译器类型推断

java - 如何在功能接口(interface)/lambda 调用中传递 Object 对象

TypeScript 在静态实现中推断出更通用的类型

typescript - typescript 中具有联合类型键的松散类型对象

C# 使类静态化?

sql - 使用存储库模式时如何在 Go 中处理数据库连接?

C# 运行多个查询的最佳方式

c# - 按联系人 ID 查询发票时 Xero api 不返回值

c# - 在 C# 中无失真地裁剪和打印图像文档

java - 如何用通用方法找出最小值?