0Pricing
C# Academy · Lezione

Varianza (in/out) con interfacce e delegate

Comprenda la varianza di C#: out per i producer (covarianza) e in per i consumer (controvarianza) su interfacce e delegate.

Varianza (in/out) con interfacce e delegate è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 3 lezioni in totale.

Panoramica sulla varianza

La varianza consente alle interfacce e ai delegati generici di funzionare con l'ereditarietà.

  • out = covarianza (produttore)
  • in = controvarianza (consumatore)
  • È sicura quando l'API produce o consuma soltanto T

Esempio di covarianza

IEnumerable<out T> è covariante: una sequenza di gatti può essere utilizzata dove è prevista una sequenza di animali.

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

Esempio di controvarianza

IComparer<in T> è controvariante: un comparatore per Animal funziona anche per Cat, perché si limita a consumare 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);
  }
}

Varianza dei delegati

Anche i delegati sono varianti: Func<out TResult> (produttore) e Action<in T> (consumatore).

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

Interfacce varianti personalizzate

Regola di progettazione: contrassegni con out i parametri utilizzati solo per produrre valori e con in quelli utilizzati solo per consumarli, così da abilitare conversioni sicure.

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

Suggerimenti sulla varianza

Suggerimenti:

  • I parametri out possono comparire solo in posizioni di output (tipi restituiti, posizioni covarianti).
  • I parametri in possono comparire solo in posizioni di input (parametri dei metodi).
  • Quando dichiara la varianza, non mescoli produzione e consumo per lo stesso T.
  • La varianza si applica alle interfacce e ai delegati, non alle classi.

Parola chiave della covarianza

Verifica rapida: quale parola chiave contrassegna un parametro di tipo covariante su un'interfaccia o un delegato?

Riepilogo

Riepilogo: utilizzi out per i produttori (covarianza) e in per i consumatori (controvarianza) su interfacce e delegati. Mantenga le API unidirezionali per abilitare conversioni sicure.

Domande Frequenti

La lezione «Varianza (in/out) con interfacce e delegate» è gratuita?

Sì — il testo completo di «Varianza (in/out) con interfacce e delegate» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 3 lezioni in totale.

Cosa imparerò in «Varianza (in/out) con interfacce e delegate»?

Comprenda la varianza di C#: out per i producer (covarianza) e in per i consumer (controvarianza) su interfacce e delegate. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 3.

Quanto tempo richiede la lezione «Varianza (in/out) con interfacce e delegate»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Metodi/tipi generici e vincoli
  2. Varianza (in/out) con interfacce e delegate
  3. Tipi di riferimento nullable (consapevolezza) e annotazioni (pattern di C# 6)
← Torna a C# Academy