Question

J'essaie d'accomplir quelque chose en C # que je fais facilement en Java. Mais avoir des problèmes. J'ai un nombre indéterminé de tableaux d'objets de type T. A implémente une interface I. J'ai besoin d'un tableau de I à la fin qui représente la somme de toutes les valeurs de tous les tableaux. Supposons qu'aucun tableau ne contiendra les mêmes valeurs.

Ce code Java fonctionne.

ArrayList<I> list = new ArrayList<I>();
for (Iterator<T[]> iterator = arrays.iterator(); iterator.hasNext();) {
    T[] arrayOfA = iterator.next();
    //Works like a charm
    list.addAll(Arrays.asList(arrayOfA));
}

return list.toArray(new T[list.size()]);

Cependant, ce code C # ne le fait pas:

List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
{
    //Problem with this
    list.AddRange(new List<T>(arrayOfA));
    //Also doesn't work
    list.AddRange(new List<I>(arrayOfA));
}
return list.ToArray();

Il est donc évident que je dois intégrer le tableau de T[] dans un IEnumerable<I> pour l’ajouter à la liste, mais je ne suis pas sûr de la meilleure façon de procéder. Des suggestions?

EDIT: Développé dans VS 2008 mais doit être compilé pour .NET 2.0.

Était-ce utile?

La solution

Le problème ici est que C # ne prend pas en charge co-variance (du moins pas avant le C 4.0, je pense) dans les génériques afin que les conversions implicites de types génériques ne fonctionnent pas.

Vous pouvez essayer ceci:

List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
{
    list.AddRange(Array.ConvertAll<T, I>(arrayOfA, t => (I)t));
}
return list.ToArray();

Pour ceux qui ont des problèmes avec cette question et qui utilisent .NET 3.5, c'est une façon un peu plus compacte de faire la même chose, avec Linq.

List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
{
    list.AddRange(arrayOfA.Cast<I>());
}
return list.ToArray();

Autres conseils

Edité pour 2.0; cela peut devenir:

static void Main() {
    IEnumerable<Foo[]> source = GetUndefinedNumberOfArraysOfObjectsOfTypeT();
    List<IFoo> list = new List<IFoo>();
    foreach (Foo[] foos in source) {
        foreach (IFoo foo in foos) {
            list.Add(foo);
        }
    }
    IFoo[] arr = list.ToArray();
}

Que diriez-vous (dans .NET 3.5):

I[] arr = src.SelectMany(x => x).Cast<I>().ToArray();

Pour afficher ceci en contexte:

using System.Collections.Generic;
using System.Linq;
using System;
interface IFoo { }
class Foo : IFoo { //  A implements an interface I
    readonly int value;
    public Foo(int value) { this.value = value; }
    public override string ToString() { return value.ToString(); }
}
static class Program {
    static void Main() {
        // I have an undefined number of arrays of objects of type T
        IEnumerable<Foo[]> source=GetUndefinedNumberOfArraysOfObjectsOfTypeT();
        // I need an array of I at the end that is the sum of
        // all values from all the arrays. 
        IFoo[] arr = source.SelectMany(x => x).Cast<IFoo>().ToArray();
        foreach (IFoo foo in arr) {
            Console.WriteLine(foo);
        }
    }
    static IEnumerable<Foo[]> GetUndefinedNumberOfArraysOfObjectsOfTypeT() {
        yield return new[] { new Foo(1), new Foo(2), new Foo(3) };
        yield return new[] { new Foo(4), new Foo(5) };
    }
}

Je suppose que vous avez essayé

list.AddRange((I[])arrayOfA);

déjà?

MODIFIER En réponse à votre commentaire, disant que ma suggestion ne fonctionnerait pas: j'ai réussi à exécuter ce code il y a une minute à peine:

using System;
using System.Collections.Generic;

namespace Tester
{
    class Program
    {
        private interface I
        {
            string GetValue();
        }

        private class A : I
        {
            private string value;

            public A(string v)
            {
                value = v;
            }

            public string GetValue()
            {
                return value;
            }
        }

        static void Main(string[] args)
        {
            List<I> theIList = new List<I>();

            foreach (A[] a in GetAList())
            {
                theIList.AddRange((I[])a);
            }

            foreach (I i in theIList)
            {
                Console.WriteLine(i.GetValue());
            }
        }

        private static IEnumerable<A[]> GetAList()
        {
            yield return new [] { new A("1"), new A("2"), new A("3") };
            yield return new [] { new A("4") };
        }
    }
}

Ou est-ce que je viens juste de répondre à une exigence?

Essayez d'ajouter une contrainte générique

où T: I

Je suppose que le problème ici est que les génériques ne réalisent pas que T implémente I. Cela peut fonctionner de déclarer explicitement T: I.

Vous pouvez également créer une boucle for et ajouter vos objets T un par un au lieu d'utiliser AddRange.

La structure de type de c # ne supporte pas cela actuellement (en considérant le Foo<T> comme un Foo<I> si X: I), on parle de covariance sur I.

La structure sous-jacente existe, et c # 4.0 est ajout de la prise en charge

Comme de tels conversions explicites sont nécessaires, la réponse de Marc étant la plus simple.

Dans votre code C #, vous n'ajoutez pas arrayOfA à la liste des résultats:

List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
    list.AddRange(arrayOfA);

return list.ToArray();

Toutefois, si vous utilisez .NET 3.5, vous pouvez le faire avec LINQ:

return (from arrayOfA in arrays
        from element in arrayOfA
        select element as I).ToArray();

Ou en utilisant les méthodes LINQ:

return arrays.SelectMany(arrayOfA => arrayOfA.Cast<I>()).ToArray();

Les tableaux d'objets de référence sont covariants en C # (il en va de même pour Java).

D'après son nom, je suppose que votre T est un type générique et non réel. Vous devez donc le limiter à un type de référence afin d'obtenir la conversion implicite de T [] en I [].

Essayez ceci:

public static I[] MergeArrays<T,I>(IEnumerable<T[]> arrays) 
    where T:class,I
{
    List<I> list = new List<I>();
    foreach(T[] array in arrays){
        list.AddRange(array);
    }
    return list.ToArray();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top