Looking for c# Keywords? Try Ask4Keywords

C# Language ковариации


пример

Когда IEnumerable<T> является подтипом другого IEnumerable<T1> ? Когда T является подтипом T1 . IEnumerable является ковариантным в своем параметре T , что означает, что отношение подтипа IEnumerable идет в том же направлении, что и T

class Animal { /* ... */ }
class Dog : Animal { /* ... */ }

IEnumerable<Dog> dogs = Enumerable.Empty<Dog>();
IEnumerable<Animal> animals = dogs;  // IEnumerable<Dog> is a subtype of IEnumerable<Animal>
// dogs = animals;  // Compilation error - IEnumerable<Animal> is not a subtype of IEnumerable<Dog>

Экземпляр ковариантного родового типа с заданным параметром типа неявно конвертируется в один и тот же общий тип с параметром менее производного типа.

Это соотношение выполняется потому, что IEnumerable производит T s, но не потребляет их. Объект, который создает Dog s, может использоваться так, как если бы он произвел Animal s.

Параметры типа Covariant объявляются с использованием ключевого слова out , потому что параметр должен использоваться только как результат .

interface IEnumerable<out T> { /* ... */ }

Параметр типа, объявленный как ковариантный, может не отображаться как вход.

interface Bad<out T>
{
    void SetT(T t);  // type error
}

Вот полный пример:

using NUnit.Framework;

namespace ToyStore
{
   enum Taste { Bitter, Sweet };

   interface IWidget
   {
      int Weight { get; }
   }

   interface IFactory<out TWidget>
       where TWidget : IWidget
   {
      TWidget Create();
   }

   class Toy : IWidget
   {
      public int Weight { get; set; }
      public Taste Taste { get; set; }
   }

   class ToyFactory : IFactory<Toy>
   {
      public const int StandardWeight = 100;
      public const Taste StandardTaste = Taste.Sweet;

      public Toy Create() { return new Toy { Weight = StandardWeight, Taste = StandardTaste }; }
   }

   [TestFixture]
   public class GivenAToyFactory
   {
      [Test]
      public static void WhenUsingToyFactoryToMakeWidgets()
      {
         var toyFactory = new ToyFactory();

         //// Without out keyword, note the verbose explicit cast:
         // IFactory<IWidget> rustBeltFactory = (IFactory<IWidget>)toyFactory;

         // covariance: concrete being assigned to abstract (shiny and new)
         IFactory<IWidget> widgetFactory = toyFactory;
         IWidget anotherToy = widgetFactory.Create();
         Assert.That(anotherToy.Weight, Is.EqualTo(ToyFactory.StandardWeight)); // abstract contract
         Assert.That(((Toy)anotherToy).Taste, Is.EqualTo(ToyFactory.StandardTaste)); // concrete contract
      }
   }
}