C# - 为什么我不能创建一个通用接口类型的IEnumerable?

Joh*_*ust 1 c# generics ienumerable interface

作为一个例子,我有一个应用程序,使水果冰沙.我可以IEnumerable列出苹果冰沙,这是有效的.

我希望能够制作一个通用的冰沙列表,IEnumerable<ISmoothie<IFruit>>以防我决定添加另一个Fruit就像橙色一样.当我尝试这样做时,代码将无法编译,我收到错误:

无法将类型'System.Collections.Generic.List>'隐式转换为'System.Collections.Generic.IEnumerable>'.存在显式转换(您是否错过了演员?)

public class Program
{
    public static void Main()
    {
        IEnumerable<ISmoothie<Apple>> appleSmoothies = new List<ISmoothie<Apple>>();   // I Can specifically make Apple Smoothies!
        IEnumerable<ISmoothie<IFruit>> genericSmoothies = new List<Smoothie<Apple>>(); // Does Not Compile - What if I want generic Smoothies? 
        Console.WriteLine("Hello World");
    }

    public class Apple : IApple
    {
        // Concrete Implimentation of an Apple
    }

    public interface IApple : IFruit
    {
        // Specific Interface for Apples
    }

    public interface IFruit
    {
        // Basic Fruit Interface for all Fruits
    }

    public class Smoothie<T> : ISmoothie<T> where T : IFruit
    {
        // Generic Fruit Smoothie
        public List<T> Ingredients {get; set;}
        public int Size {get; set;}
        public void Drink()
        {
            // Drink Logic
        }
    }

    public interface ISmoothie<T> where T : IFruit
    {
        List<T> Ingredients {get; set;}
        int Size {get; set;}
        void Drink();
    }
}
Run Code Online (Sandbox Code Playgroud)

AAA*_*ddd 5

您需要将out参数添加到接口以指定协方差

public interface ISmoothie<out T> where T : IFruit
{
}
Run Code Online (Sandbox Code Playgroud)

out(泛型修饰符)(C#参考)

对于泛型类型参数,out关键字指定type参数是协变的.您可以在通用接口和委托中使用out关键字.

协方差使您可以使用比泛型参数指定的派生类型更多的派生类型.这允许隐式转换实现协变接口和委托类型的隐式转换的类.参考类型支持协方差和逆变,但值类型不支持它们.

更新

使用out参数时有限制,

public class Smoothie<T> : ISmoothie<T> where T : IFruit
{
   // Generic Fruit Smoothie
   public T Type { get; set; } // we can do this
}

public interface ISmoothie<out T> where T : IFruit
{
   T Type { get; set; } // compiler error CS1961 Invalid variance: 
}
Run Code Online (Sandbox Code Playgroud)

out T表示类型T仅限于在泛型类,接口或方法的方法中仅作为返回(出站)值出现

  • 值得注意的是,这只有效,因为 OP 没有向我们显示任何以“T”作为参数的“ISmoothie&lt;out T&gt;”成员。 (2认同)