将类型为T的数组转换为类型I的数组,其中T在C#中实现I

我试图在C#中完成一些我在Java中轻松完成的事情。 但有点麻烦。 我有一个未定义数量的T类型的对象数组.A实现了一个接口I.我需要一个I的数组,它是所有数组中所有值的总和。 假设没有数组将包含相同的值。

这个Java代码有效。

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

但是这个C#代码没有:

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

因此很明显我需要以某种方式将T[]数组放入IEnumerable以添加到列表中,但我不确定这样做的最佳方法是什么? 有什么建议?

编辑:在VS 2008中开发但需要为.NET 2.0编译。

这里的问题是C#在generics中不支持协方差 (至少在C#4.0之前,我认为),因此generics类型的隐式转换将不起作用。

你可以试试这个:

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

对于那些在这个问题上喋喋不休并使用.NET 3.5的人来说,使用Linq这是一种稍微紧凑的方式来做同样的事情。

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

编辑为2.0; 它可以成为:

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

怎么样(在.NET 3.5中):

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

要在上下文中显示:

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

我猜你已经尝试过了

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

已经?

编辑回复你的评论说我的建议不起作用:我在一分钟前成功运行了这段代码:

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

或者我只是提出要求?

尝试添加通用约束

T:我

我猜这里的问题是generics并没有意识到T实现了它。它可能会明确地声明T:I。

您也可以执行for循环并一次添加一个T对象,而不是使用AddRange。

c#的类型结构目前不支持这一点(如果X:I将Foo视为Foo )这在I上称为协方差。

底层框架确实如此,而c#4.0正在添加对它的支持

由于需要明确演员,Marc的答案是最简单的。

在您的C#代码中,您没有将arrayOfA添加到结果列表中:

 List list = new List(); foreach (T[] arrayOfA in arrays) list.AddRange(arrayOfA); return list.ToArray(); 

但是,如果您使用的是.NET 3.5,则可以使用LINQ执行此操作:

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

或者使用LINQ方法:

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

引用对象的数组在C#中是协变的 (Java也是如此)。

从名称来看,我猜你的T是通用的而不是真实的类型,所以你必须将它限制为引用类型才能获得从T []到I []的隐式转换。

试试这个:

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