Considere un ejemplo:
Tengo una interfaz como esta. Necesito que esta interfaz sea covariante, lo que significa que debo declarar mi genérico como "out" y usar IEnumerable en lugar de list, y eso es todo. Usaré esto solo para obtener los elementos que necesito, nada que insertar.
public interface IFoo<out T> { IEnumerable<T> Items { get; } }Y luego tengo mi clase concreta declarada así:
public class Foo : IFoo<Item> { // I have an error here : Type IList doesn't match the expected type IEnmerable IList<Item> Items { get; set; } }Y me pregunto ¿por qué eso no es posible? Quiero decir que IList hereda de IEnumerable y este tipo de código funciona completamente bien.
public IEnumerable<Item> GetItems() { return new List() { new Item())}; }¿Por qué se puede hacer? ¿Cuáles son las soluciones?
Mi única solución es que podría crear una propiedad o método adicional como este
public IEnumerable<Item> GetEnumerableItems() { return Items; }Pero me parece demasiado complicado. Creo que podría haber una solución más limpia.
Esto no es compatible con el tiempo de ejecución. Si está implementando una interfaz que tiene una propiedad que devuelve un tipo particular, debe hacer coincidir ese tipo de retorno exactamente en su implementación.
La covarianza del tipo de retorno se agregó en C# 9, pero no se aplica aquí (consulte el comentario de @JeroenMostert).
Puede solucionar esto utilizando una implementación de interfaz explícita:
public class Foo : IFoo<Item> { IList<Item> Items { get; set; } IEnumerable<Item> IFoo<Item>.Items => Items; }SharpLab .
Los consumidores que tienen un Foo pueden acceder a Foo.Items y obtener un IList<Item> . Los consumidores que solo tienen un IFoo<Item> pueden acceder a IFoo<Item>.Items y obtendrán un IEnumerable<Item> .