Existe-t-il un moyen de convertir les listes génériques en listes de types de classes d'interface / de base?

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

  •  06-07-2019
  •  | 
  •  

Question

J'essaie de montrer à quelqu'un une utilisation des interfaces dans une situation folle qu'ils ont créée. Ils ont plusieurs objets non liés dans des listes et doivent effectuer une opération sur deux propriétés de chaîne dans chaque objet. Je souligne que s'ils définissent les propriétés dans le cadre d'une interface, ils peuvent utiliser l'objet interface comme type d'un paramètre de méthode qui agit sur celui-ci. par exemple:

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

Cela semble être une bonne chose, mais les listes sur lesquelles il faut travailler ne sont pas (et ne devraient pas) être déclarées avec l'interface comme paramètre de type. Cependant, il ne semble pas que vous puissiez utiliser un paramètre de type différent. Par exemple, cela échoue et je ne comprends pas pourquoi:

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

Je peux utiliser le membre Enumerable.Cast<T> pour ce faire, mais je recherchais une méthode qui pourrait également fonctionner dans .NET 2.0. Il semble que cela devrait être possible. Qu'est-ce que je rate?

Était-ce utile?

La solution

Le problème vient de la méthode, pas de la manière dont elle s'appelle .....

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

Autres conseils

La raison de son échec est que les génériques ne présentent pas (encore) de variance en C #.

En ce qui concerne le correctif pour IEnumerable < T > ;, essayez cependant ceci:

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

EDIT: L’autre réponse existante est meilleure que ce qui précède dans ce cas particulier, mais je vais laisser cela ici comme une chose généralement utile si vous avez réellement besoin de & "Convertir &"; la séquence.

Vous pouvez simplement utiliser un foreach sur les listes que vous avez. Le <=> fait un casting intégré. Donc, si vous prenez la boucle de la fonction, vous pouvez écrire quelque chose comme

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

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

Ce que vous voulez s'appelle & "; covariance d'interface &"; et n'est pas supporté par C # pour le moment. Vous pouvez en apprendre davantage à ce sujet sur Le blog de Eric Lippert .

Cela ne répond pas à votre question (ni au but de l'exercice, je suppose :), mais j'utiliserais simplement la réflexion dans ce cas en associant des attributs spéciaux aux propriétés d'intérêt.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top