0Pricing
C# Academy · Aula

Variância (in/out) com interfaces e delegados

Entenda a variância do C#: out para produtores (covariância) e in para consumidores (contravariância) em interfaces e delegados.

Variância (in/out) com interfaces e delegados é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 3. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 3 aulas no total.

Visão geral da variância

Variância permite que interfaces e delegados genéricos funcionem com herança.

  • out = covariância (produtor)
  • in = contravariância (consumidor)
  • É seguro quando a API apenas produz ou apenas consome T

Demonstração de covariância

IEnumerable<out T> é covariante: uma sequência de gatos pode ser usada onde se espera uma sequência de animais.

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

Demonstração de contravariância

IComparer<in T> é contravariante: um comparador para Animal também funciona para Cat, pois apenas consome 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);
  }
}

Variância de delegados

Os delegados também são variantes: Func<out TResult> (produtor) e Action<in T> (consumidor).

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

Interfaces variantes personalizadas

Regra de projeto: marque os parâmetros usados apenas para produzir como out e os usados apenas para consumir como in para habilitar conversões seguras.

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

Dicas sobre variância

Dicas:

  • Os parâmetros out só podem aparecer em posições de saída (tipos de retorno e posições covariantes).
  • Os parâmetros in só podem aparecer em posições de entrada (parâmetros de métodos).
  • Não misture produção e consumo para o mesmo T ao declarar a variância.
  • A variância se aplica a interfaces e delegados, não a classes.

Palavra-chave da covariância

Verificação rápida: qual palavra-chave marca um parâmetro de tipo covariante em uma interface ou delegado?

Recapitulação

Recapitulação: use out para produtores (covariância) e in para consumidores (contravariância) em interfaces e delegados. Mantenha as APIs unidirecionais para habilitar conversões seguras.

Perguntas Frequentes

A aula “Variância (in/out) com interfaces e delegados” é grátis?

Sim — o texto completo de “Variância (in/out) com interfaces e delegados” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 3 aulas no total.

O que vou aprender em “Variância (in/out) com interfaces e delegados”?

Entenda a variância do C#: out para produtores (covariância) e in para consumidores (contravariância) em interfaces e delegados. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 3.

Quanto tempo leva a aula “Variância (in/out) com interfaces e delegados”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Métodos/tipos genéricos e restrições
  2. Variância (in/out) com interfaces e delegados
  3. Tipos de referência anuláveis (conscientização) e anotações (padrões do C# 6)
← Voltar para C# Academy