Sto cercando di realizzare qualcosa in C # che faccio facilmente in Java. Ma avendo qualche problema. Ho un numero indefinito di matrici di oggetti di tipo T. A implementa un’interfaccia I. Ho bisogno di un array di I alla fine che è la sum di tutti i valori di tutti gli array. Assumere che nessun array conterrà gli stessi valori.
Questo codice Java funziona.
ArrayList list = new ArrayList(); for (Iterator 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()]);
Tuttavia questo codice C # non:
List list = new List(); foreach (T[] arrayOfA in arrays) { //Problem with this list.AddRange(new List(arrayOfA)); //Also doesn't work list.AddRange(new List(arrayOfA)); } return list.ToArray();
Quindi è ovvio che ho bisogno di ottenere in qualche modo l’array di T[]
in un IEnumerable
da aggiungere alla lista ma non sono sicuro che sia il modo migliore per farlo? Eventuali suggerimenti?
EDIT: lo sviluppo in VS 2008, ma ha bisogno di compilare per .NET 2.0.
Il problema qui è che C # non supporta la co-varianza (almeno non prima di C # 4.0, credo) in generici, quindi le conversioni implicite di tipi generici non funzioneranno.
Potresti provare questo:
List list = new List(); foreach (T[] arrayOfA in arrays) { list.AddRange(Array.ConvertAll(arrayOfA, t => (I)t)); } return list.ToArray();
Per chiunque abbia a che fare con questa domanda e stia usando .NET 3.5, questo è un modo leggermente più compatto di fare la stessa cosa, usando Linq.
List list = new List(); foreach (T[] arrayOfA in arrays) { list.AddRange(arrayOfA.Cast()); } return list.ToArray();
Modificato per 2.0; può diventare:
static void Main() { IEnumerable source = GetUndefinedNumberOfArraysOfObjectsOfTypeT(); List list = new List (); foreach (Foo[] foos in source) { foreach (IFoo foo in foos) { list.Add(foo); } } IFoo[] arr = list.ToArray(); }
Che ne dici di (in .NET 3.5):
I[] arr = src.SelectMany(x => x).Cast().ToArray();
Per mostrare questo nel contesto:
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 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().ToArray(); foreach (IFoo foo in arr) { Console.WriteLine(foo); } } static IEnumerable GetUndefinedNumberOfArraysOfObjectsOfTypeT() { yield return new[] { new Foo(1), new Foo(2), new Foo(3) }; yield return new[] { new Foo(4), new Foo(5) }; } }
Suppongo tu abbia provato
list.AddRange((I[])arrayOfA);
già?
EDIT In risposta al tuo commento dicendo che il mio suggerimento non funzionava: ho eseguito con successo questo codice solo un minuto fa:
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 theIList = new List(); foreach (A[] a in GetAList()) { theIList.AddRange((I[])a); } foreach (I i in theIList) { Console.WriteLine(i.GetValue()); } } private static IEnumerable GetAList() { yield return new [] { new A("1"), new A("2"), new A("3") }; yield return new [] { new A("4") }; } } }
O forse ho solo un obbligo?
Prova ad aggiungere un vincolo generico
dove T: I
Immagino che il problema qui sia che i generici non si rendono conto che T implementa I. Potrebbe funzionare per dichiarare esplicitamente T: I.
Puoi anche fare un ciclo for e aggiungere gli oggetti T uno alla volta invece di usare AddRange.
La struttura dei tipi di c # attualmente non supporta questo (trattando il Foo
come Foo
se X: I) questo è chiamato covarianza su I.
Il framework sottostante funziona e c # 4.0 sta aggiungendo il supporto per questo
Dato che tali cast espliciti sono richiesti, la risposta di Marc è la più semplice.
Nel tuo codice C # non stai aggiungendo l’arrayOfA all’elenco dei risultati:
List list = new List(); foreach (T[] arrayOfA in arrays) list.AddRange(arrayOfA); return list.ToArray();
Tuttavia, se si utilizza .NET 3.5, è ansible farlo con LINQ:
return (from arrayOfA in arrays from element in arrayOfA select element as I).ToArray();
O usando i metodi LINQ:
return arrays.SelectMany(arrayOfA => arrayOfA.Cast()).ToArray();
Le matrici di oggetti di riferimento sono covarianti in C # (lo stesso vale per Java).
Dal nome, immagino che il tuo T sia un tipo generico e non reale, quindi devi restringerlo a un tipo di riferimento per ottenere la conversione implicita da T [] a I [].
Prova questo:
public static I[] MergeArrays(IEnumerable arrays) where T:class,I { List list = new List(); foreach(T[] array in arrays){ list.AddRange(array); } return list.ToArray(); }