Почему я не могу сделать IEnumerable универсального типа интерфейса? - PullRequest
0 голосов
/ 05 февраля 2019

В качестве примера у меня есть приложение, которое делает фруктовые смузи.Я могу сделать список IEnumerable смузи Apple, и это работает.

Я хочу иметь возможность составить общий список смузи IEnumerable<ISmoothie<IFruit>> на случай, если я решу добавить еще один фрукт, как, например, апельсин.Когда я пытаюсь это сделать, код не компилируется, и я получаю сообщение об ошибке:

Не удается неявно преобразовать тип '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();
    }
}

1 Ответ

0 голосов
/ 05 февраля 2019

Вам необходимо добавить параметр out в свой интерфейс, чтобы указать Ковариация

public interface ISmoothie<out T> where T : IFruit
{
}

out (универсальный модификатор) (C # Reference)

Для параметров универсального типа ключевое слово out указывает, что параметр типа является ковариантным.Вы можете использовать ключевое слово out в универсальных интерфейсах и делегатах.

Covariance позволяет использовать более производный тип, чем тот, который задан универсальным параметром .Это позволяет неявное преобразование классов, которые реализуют ковариантные интерфейсы, и неявное преобразование типов делегатов.Ковариация и контравариантность поддерживаются для ссылочных типов, но не поддерживаются для типов значений.

Обновление

Существуют ограничения при использовании параметра 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: 
}

out T означает, что тип T может отображаться только как возвращенное (исходящее) значение в методах универсального класса, интерфейса или метода

...