C# Academy · Oppitunti

Varianssi (in/out) rajapinnoissa ja delegaateissa

Perehtykää C#:n varianssiin: out tuottajille (kovarianssi) ja in kuluttajille (kontravarianssi) rajapinnoissa ja delegaateissa.

Oppitunti 2/38 vaihetta

Varianssi (in/out) rajapinnoissa ja delegaateissa on ilmainen C# Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/3. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu C# Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C# Academy-kurssilla on yhteensä 3 oppituntia.

Varianssin yleiskatsaus

Varianssin ansiosta geneeriset rajapinnat ja delegaatit voivat toimia perintähierarkian kanssa.

  • out = kovarianssi (tuottaja)
  • in = kontravarianssi (kuluttaja)
  • Turvallista, kun API tuottaa tai kuluttaa ainoastaan tyyppiä T

Kovarianssiesimerkki

IEnumerable<out T> on kovariantti: kissojen jonoa voidaan käyttää siellä, missä odotetaan eläinten jonoa.

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

Kontravarianssiesimerkki

IComparer<in T> on kontravariantti: Animal-vertailija toimii myös Cat-tyypin kanssa, koska se vain kuluttaa T: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);
  }
}

Delegaattien varianssi

Delegaatit ovat myös variantteja: Func<out TResult> (tuottaja) ja Action<in T> (kuluttaja).

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

Mukautetut variantit rajapinnat

Suunnittelusääntö: merkitkää vain tuottamiseen käytettävät parametrit out-merkinnällä ja vain kuluttamiseen käytettävät parametrit in-merkinnällä turvallisten muunnosten mahdollistamiseksi.

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

Varianssivinkit

Vinkit:

  • out-parametreja saa käyttää vain tulospaikoissa (palautustyypeissä ja kovarianssia tukevissa kohdissa).
  • in-parametreja saa käyttää vain syötepaikoissa (metodien parametreina).
  • Älkää yhdistäkö saman T-tyypin tuottamista ja kuluttamista varianssia määritettäessä.
  • Varianssi koskee rajapintoja ja delegaatteja, ei luokkia.

Kovarianssin avainsana

Pikatarkistus: Millä avainsanalla merkitään kovariantti tyyppiparametri rajapinnassa tai delegaatissa?

Kertaus

Kertaus: Käyttäkää rajapinnoissa ja delegaateissa tuottajille out-merkintää (kovarianssi) ja kuluttajille in-merkintää (kontravarianssi). Pitäkää API:t yksisuuntaisina turvallisten muunnosten mahdollistamiseksi.

Aloita maksutta

Opi C# tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
93
Oppitunnit
346

Usein kysytyt kysymykset

Onko oppitunti ”Varianssi (in/out) rajapinnoissa ja delegaateissa” ilmainen?

Kyllä – oppitunnin ”Varianssi (in/out) rajapinnoissa ja delegaateissa” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko C# Academy-kurssin, päivitä CoddyKit PROhon. C# Academy-kurssilla on yhteensä 3 oppituntia.

Mitä opin oppitunnilla ”Varianssi (in/out) rajapinnoissa ja delegaateissa”?

Perehtykää C#:n varianssiin: out tuottajille (kovarianssi) ja in kuluttajille (kontravarianssi) rajapinnoissa ja delegaateissa. Harjoittelet C# Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C# Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C# Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/3.

Kuinka kauan ”Varianssi (in/out) rajapinnoissa ja delegaateissa”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C# Academy-oppitunnilla?

Kyllä. Jokainen C# Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Geneeriset metodit ja tyypit sekä rajoitteet
  2. Varianssi (in/out) rajapinnoissa ja delegaateissa
  3. Nullable-viitetyypit (perustiedot) ja annotaatiot (C# 6 -mallit)
← Takaisin: C# Academy