¿Hay alguna forma de emitir listas genéricas a listas de tipos de interfaz / clase base?

StackOverflow https://stackoverflow.com/questions/188769

  •  06-07-2019
  •  | 
  •  

Pregunta

Estoy tratando de mostrarle a alguien un uso de interfaces en una situación loca que han creado. Tienen varios objetos no relacionados en las listas y necesitan realizar una operación en dos propiedades de cadena en cada objeto. Estoy señalando que si definen las propiedades como parte de una interfaz, pueden usar el objeto de interfaz como el tipo para un parámetro de método que actúa sobre él; por ejemplo:

void PrintProperties(IEnumerable<ISpecialProperties> list)
{
    foreach (var item in list)
    {
        Console.WriteLine("{0} {1}", item.Prop1, item.Prop2);
    }
}

Parece que todo está bien, pero las listas que necesitan ser trabajadas no están (y no deberían) declararse con la interfaz como parámetro de tipo. Sin embargo, no parece que pueda enviar a un parámetro de tipo diferente. Por ejemplo, esto falla y no puedo entender por qué:

using System;
using System.Collections.Generic;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Test> myList = new List<Test>();
            for (int i = 0; i < 5; i++)
            {
                myList.Add(new Test());
            }

            PrintList((IEnumerable<IDoSomething>)myList);
        }

        static void PrintList(IEnumerable<IDoSomething> list)
        {
            foreach (IDoSomething item in list)
            {
                item.DoSomething();
            }
        }
    }

    interface IDoSomething
    {
        void DoSomething();
    }

    public class Test : IDoSomething
    {
        public void DoSomething()
        {
            Console.WriteLine("Test did it!");
        }
    }
}

Yo puedo usar el miembro Enumerable.Cast<T> para hacer esto, pero estaba buscando un método que también pudiera funcionar en .NET 2.0. Parece que esto debería ser posible; ¿Qué me estoy perdiendo?

¿Fue útil?

Solución

El problema está en el método, no en cómo se llama .....

void PrintProperties<SP>(IEnumerable<SP> list) where SP: ISpecialProperties
{
    foreach (var item in list)
    {
        Console.WriteLine("{0} {1}", item.Prop1, item.Prop2);
    }
}

Otros consejos

La razón por la que falla es porque los genéricos no muestran variación en C # (todavía).

En cuanto a la solución para IEnumerable < T > ;, sin embargo, intente esto:

public static IEnumerable<TBase> SafeConvert<TBase, TDerived>(IEnumerable<TDerived> source)
    where TDerived : TBase
{
    foreach (TDerived element in source)
    {
        yield return element; // Implicit conversion to TBase
    }
}

EDITAR: La otra respuesta existente es mejor que la anterior para este caso particular, pero lo dejaré aquí como algo generalmente útil si realmente necesita " convert " la secuencia.

Puede usar un foreach en las listas que tiene. El <=> hace un molde incorporado. Entonces, si eliminas el bucle de la función, puedes escribir algo como

List<Test> myList = new List<Test>();
for (int i = 0; i < 5; i++)
{
   myList.Add(new Test());
}

foreach (IDoSomething item in myList)
{
   item.DoSomething();
}

Lo que quieres se llama " interfaz covarianza " y no es compatible con C # en este momento. Puede leerlo en Blog de Eric Lippert .

Esto no responde a su pregunta (o el punto del ejercicio, supongo :), pero simplemente usaría la reflexión en este caso adjuntando atributos especiales a las propiedades de interés.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top