我正在尝试使用Java轻松完成C#中的某些操作。但有点麻烦。 我有一个未定义数量的T类型的对象数组。 A实现接口I. 我需要一个I的数组,它是所有数组中所有值的总和。 假设没有数组包含相同的值。
这个Java代码可以工作。
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()]);
但是这个C#代码没有:
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();
所以很明显我需要以某种方式将T[]
的数组放入IEnumerable<I>
添加到列表中,但我不确定最好的方法吗?有什么建议吗?
编辑:在VS 2008中开发但需要为.NET 2.0编译。
答案 0 :(得分:7)
编辑为2.0;它可以成为:
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();
}
(在.NET 3.5中):
I[] arr = src.SelectMany(x => x).Cast<I>().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<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) };
}
}
答案 1 :(得分:5)
这里的问题是C#在泛型中不支持co-variance(至少在C#4.0之前,我认为),因此泛型类型的隐式转换将不起作用。
你可以试试这个:
List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
{
list.AddRange(Array.ConvertAll<T, I>(arrayOfA, t => (I)t));
}
return list.ToArray();
对于那些在这个问题上喋喋不休并使用.NET 3.5的人来说,这是一种使用Linq做同样事情的更紧凑的方法。
List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
{
list.AddRange(arrayOfA.Cast<I>());
}
return list.ToArray();
答案 2 :(得分:3)
我猜你已经尝试了
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<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") };
}
}
}
或者我只是提出要求?
答案 3 :(得分:1)
尝试添加通用约束
其中T:我
答案 4 :(得分:1)
我猜这里的问题是泛型没有意识到T实现了它。它可能会明确地声明T:I。
此外,您可以执行for循环并一次添加一个T对象,而不是使用AddRange。
答案 5 :(得分:1)
c#的类型结构目前不支持这一点(如果X,则将Foo<T>
视为Foo<I>
:I)这在I上称为协方差。
底层框架和c# 4.0 is adding support for it
由于需要明确演员,Marc的答案是最简单的。
答案 6 :(得分:0)
在C#代码中,您没有将arrayOfA添加到结果列表中:
List<I> list = new List<I>();
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<I>()).ToArray();
答案 7 :(得分:0)
Arrays of reference objects are covariant in C#(Java也是如此)。
从名称来看,我猜你的T是通用的而不是真实的类型,所以你必须将它限制为引用类型才能获得从T []到I []的隐式转换。
试试这个:
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();
}