Frage

Ich versuche, etwas in C # zu erreichen, die ich in Java leicht tun. Aber mit etwas Mühe. Ich habe eine nicht definierte Anzahl von Arrays von Objekten des Typs T. A implementiert eine Schnittstelle I. Ich muss eine Reihe von I am Ende, dass die Summe aller Werte von allen Arrays ist. Nehmen wir keine Arrays die gleichen Werte enthalten.

Dieser Java-Code funktioniert.

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()]);

Doch dieser C # -Code nicht:

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

Es ist also offensichtlich, ich brauche irgendwie das Array von T[] in eine IEnumerable<I> kennen zu der Liste hinzufügen, aber ich bin nicht sicher, den besten Weg, dies zu tun? Irgendwelche Vorschläge?

EDIT: Die Entwicklung in VS 2008, muss aber für .NET 2.0 kompilieren.

War es hilfreich?

Lösung

Das Problem hier ist, dass C # nicht a href unterstützt <= "http://weblogs.asp.net/astopford/archive/2006/12/28/c-generics-covariance.aspx" rel = "nofollow noreferrer "> Kovarianz (zumindest nicht bis C # 4.0, glaube ich) in den Bereichen Generika so implizite Konvertierungen von generischen Typen werden nicht funktionieren.

Sie könnten versuchen, diese:

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

Für alle, die sich über diese Frage strumbles und wird mit .NET 3.5, ist dies eine etwas kompaktere Art und Weise das Gleiche zu tun, mit Linq.

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

Andere Tipps

Herausgegeben für 2,0; es kann sich:

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

Wie wäre es (in .NET 3.5):

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

Um dies zu zeigen, im Kontext:

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

Ich nehme an, Sie haben versucht,

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

schon?

Bearbeiten In Antwort auf Ihren Kommentar zu sagen, dass mein Vorschlag nicht funktionieren würde: Ich habe diesen Code erfolgreich lief nur eine Minute vor:

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

Oder habe ich nur eine Anforderung Durcheinander?

Versuchen Sie das Hinzufügen einer generische Einschränkung

where T: I

Ich vermute, hier das Problem ist, dass Generika nicht erkennen, dass T I. implementiert Es könnte ausdrücklich T erklären arbeiten: I.

Auch Sie könnten ein for-Schleife tun und fügen Sie Ihre T einen nach dem anderen Objekten anstelle AddRange zu verwenden.

Der Typ Struktur von c # derzeit nicht unterstützt dies (den Foo<T> als Foo<I> Behandlung, wenn X: I). Kovarianzstruktur auf I bezeichnet wird,

Der zugrunde liegende Framework der Fall ist, und c # 4.0 ist Unterstützung Zugabe für sie

Als solche explizite Casts erforderlich sind, Marc Antwort die einfachste zu sein.

In Ihrer C # -Code Sie hinzufügen, nicht die arrayOfA auf die Ergebnisliste:

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

return list.ToArray();

Wenn Sie jedoch .NET 3.5 verwenden Sie können dies tun, mit LINQ:

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

oder mit LINQ Methoden:

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

Arrays von Referenzobjekten sind covariant in C # (das gleiche gilt für Java).

Von den Namen, ich denke, dass Ihr T eine generisch ist und kein echter Typ, so dass Sie es auf einen Referenztyp zu beschränken, um die implizite Konvertierung von T [] I [] zu erhalten.

Versuchen Sie folgendes:

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();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top