Convertire un array di tipo T in un array di tipo I dove T implementa I in C #

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