0Pricing
C# Academy · Lekcja

Wariancja (in/out) z interfejsami i delegatami

Poznaj wariancję w C#: out dla producentów (kowariancja) oraz in dla konsumentów (kontrawariancja) w interfejsach i delegatach.

Wariancja (in/out) z interfejsami i delegatami to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 3 lekcji w sumie.

Przegląd wariancji

Wariancja pozwala generycznym interfejsom i delegatom współpracować z dziedziczeniem.

  • out = kowariancja (producent)
  • in = kontrawariancja (konsument)
  • Jest bezpieczna, gdy API tylko produkuje wartości typu T albo tylko je konsumuje

Demonstracja kowariancji

IEnumerable<out T> jest kowariantny: sekwencję kotów można wykorzystać tam, gdzie oczekiwana jest sekwencja zwierząt.

using System;
using System.Collections.Generic;

public class Animal { public virtual string Name() { return "animal"; } }
public class Cat : Animal { public override string Name() { return "cat"; } }

public class Program
{
  static void PrintAll(IEnumerable<Animal> animals)
  {
    foreach (Animal a in animals)
    {
      Console.WriteLine(a.Name());
    }
  }

  public static void Main(string[] args)
  {
    List<Cat> cats = new List<Cat>();
    cats.Add(new Cat());
    // IEnumerable<Cat> -> IEnumerable<Animal> is allowed (out T)
    PrintAll(cats);
  }
}

Demonstracja kontrawariancji

IComparer<in T> jest kontrawariantny: komparator dla Animal działa również dla Cat, ponieważ tylko konsumuje T.

using System;
using System.Collections.Generic;

public class Animal { public string N; public Animal(string n){ N=n; } }
public class Cat : Animal { public Cat(string n) : base(n) {} }

// Comparer can compare any Animals
public class AnimalNameComparer : IComparer<Animal>
{
  public int Compare(Animal x, Animal y)
  {
    return string.Compare(x == null ? "" : x.N, y == null ? "" : y.N, StringComparison.Ordinal);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    List<Cat> cats = new List<Cat>();
    cats.Add(new Cat("Miso"));
    cats.Add(new Cat("Ada"));
    // IComparer<Animal> can be used as IComparer<Cat> (in T)
    cats.Sort(new AnimalNameComparer());
    foreach (Cat c in cats) Console.WriteLine(c.N);
  }
}

Wariancja delegatów

Delegaty również mogą być wariantowe: Func<out TResult> (producent) i Action<in T> (konsument).

using System;

public class Animal { public virtual string Speak(){ return "???"; } }
public class Cat : Animal { public override string Speak(){ return "meow"; } }

public class Program
{
  static Animal MakeAnimal() { return new Animal(); }
  static void HandleAnimal(Animal a) { Console.WriteLine(a.Speak()); }

  public static void Main(string[] args)
  {
    // Func<Cat> can be used where Func<Animal> is expected? Yes, because TResult is out.
    Func<Animal> maker = new Func<Cat>(delegate { return new Cat(); });
    Console.WriteLine(maker().Speak());

    // Action<Animal> can be used where Action<Cat> is expected? Yes, because T is in.
    Action<Cat> catSink = new Action<Animal>(HandleAnimal);
    catSink(new Cat());
  }
}

Własne wariantowe interfejsy

Zasada projektowania: parametry używane wyłącznie przez producenta oznaczaj jako out, a używane wyłącznie przez konsumenta jako in, aby umożliwić bezpieczne konwersje.

using System;

// Producer-only interface: out T
public interface ISource<out T>
{
  T Get();
}

// Consumer-only interface: in T
public interface ISink<in T>
{
  void Put(T item);
}

public class Animal { public string N; }
public class Cat : Animal { }

public class CatSource : ISource<Cat>
{
  public Cat Get() { return new Cat(); }
}

public class AnimalSink : ISink<Animal>
{
  public void Put(Animal a) { Console.WriteLine("Got animal"); }
}

public class Program
{
  public static void Main(string[] args)
  {
    ISource<Animal> animals = new CatSource(); // out T allows upcast
    ISink<Cat> cats = new AnimalSink();        // in T allows down-assign
    animals.Get();
    cats.Put(new Cat());
  }
}

Wskazówki dotyczące wariancji

Wskazówki:

  • Parametry oznaczone out mogą występować tylko w pozycjach wyjściowych (typach zwracanych i miejscach kowariantnych).
  • Parametry oznaczone in mogą występować tylko w pozycjach wejściowych (parametrach metod).
  • Podczas deklarowania wariancji nie mieszaj produkowania i konsumowania tego samego T.
  • Wariancja dotyczy interfejsów i delegatów, a nie klas.

Słowo kluczowe kowariancji

Szybkie sprawdzenie: Które słowo kluczowe oznacza kowariantny parametr typu w interfejsie lub delegacie?

Podsumowanie

Podsumowanie: W interfejsach i delegatach używaj out dla producentów (kowariancja) oraz in dla konsumentów (kontrawariancja). Projektuj interfejsy jednokierunkowo, aby umożliwić bezpieczne konwersje.

Często zadawane pytania

Czy lekcja „Wariancja (in/out) z interfejsami i delegatami” jest bezpłatna?

Tak — pełny tekst „Wariancja (in/out) z interfejsami i delegatami” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 3 lekcji w sumie.

Co nauczysz się w „Wariancja (in/out) z interfejsami i delegatami”?

Poznaj wariancję w C#: out dla producentów (kowariancja) oraz in dla konsumentów (kontrawariancja) w interfejsach i delegatach. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.

Ile czasu zajmuje lekcja „Wariancja (in/out) z interfejsami i delegatami”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Metody i typy generyczne; ograniczenia
  2. Wariancja (in/out) z interfejsami i delegatami
  3. Typy referencyjne dopuszczające null (świadomość) i adnotacje (wzorce z C# 6)
← Powrót do C# Academy