0Pricing
C# Academy · Lección

Varianza (in/out) con interfaces y delegados

Comprenda la varianza de C#: out para productores (covarianza) e in para consumidores (contravarianza) en interfaces y delegados.

Varianza (in/out) con interfaces y delegados es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 2 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 3 lecciones en total.

Descripción general de la varianza

La varianza permite que las interfaces y los delegados genéricos funcionen con la herencia.

  • out = covarianza (productor)
  • in = contravarianza (consumidor)
  • Es segura cuando la API solo produce o solo consume T

Demostración de covarianza

IEnumerable<out T> es covariante: una secuencia de gatos puede usarse donde se espera una secuencia de animales.

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

Demostración de contravarianza

IComparer<in T> es contravariante: un comparador para Animal también funciona para Cat porque solo consume 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 de delegados

Los delegados también admiten varianza: Func<out TResult> (productor) y 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

Regla de diseño: marque los parámetros que solo producen valores como out y los que solo consumen valores como in para habilitar conversiones 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());
  }
}

Consejos sobre varianza

Consejos:

  • Los parámetros out solo pueden aparecer en posiciones de salida (tipos de retorno y posiciones covariantes).
  • Los parámetros in solo pueden aparecer en posiciones de entrada (parámetros de métodos).
  • No mezcle la producción y el consumo del mismo T al declarar la varianza.
  • La varianza se aplica a interfaces y delegados, no a clases.

Palabra clave de covarianza

Comprobación rápida: ¿Qué palabra clave marca un parámetro de tipo covariante en una interfaz o delegado?

Repaso

Repaso: Use out para los productores (covarianza) y in para los consumidores (contravarianza) en interfaces y delegados. Mantenga las API unidireccionales para habilitar conversiones seguras.

Preguntas frecuentes

¿La lección «Varianza (in/out) con interfaces y delegados» es gratis?

Sí — el texto completo de «Varianza (in/out) con interfaces y delegados» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 3 lecciones en total.

¿Qué aprenderé en «Varianza (in/out) con interfaces y delegados»?

Comprenda la varianza de C#: out para productores (covarianza) e in para consumidores (contravarianza) en interfaces y delegados. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 3.

¿Cuánto tiempo toma la lección «Varianza (in/out) con interfaces y delegados»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Métodos/tipos genéricos y restricciones
  2. Varianza (in/out) con interfaces y delegados
  3. Tipos de referencia anulables (nociones) y anotaciones (patrones de C# 6)
← Volver a C# Academy