簡體   English   中英

接口繼承與通用列表

[英]Interface inheritance with generic lists

我想為一個簡單的項目構建一個生產者和消費者的通用系統。

我現在擁有的是什么

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。 這是一些差異問題嗎? 這有什么問題?

這很棘手。 你可以使用co / contravariance,但......

我會稍微簡化代碼。 只是為了關閉編譯器,你可以這樣做:

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);
}

aaaand它不會編譯。 因為簡單地說如果你說出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);這樣的抽象簽名bool CanProcess(IMessage); IMessage Process(IMessage); bool CanProcess(IMessage); IMessage Process(IMessage); 並投入內部。 您也可以使用自定義屬性和反射稍微好一些,但同樣,不僅僅是使用C#編譯器。

如果您計划使用這些接口實現典型的生產者,消費者模式,請首先查看此答案


如果您希望IConsumer<TMessage> 也是 IConsumer<TMessageBase> ,其中TMessageBaseTMessage繼承或實現的任何類型,那么您需要使您的泛型參數協變。 使用out修飾符。

public interface IConsumer<out T>    {    }

現在IConsumer<Message1>可以分配給IConsumer<IMessage> ,因為Message1實現了IMessage

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM