T 형 배열을 Type I 배열로 변환하여 T는 C#에서 I를 구현합니다.
-
06-07-2019 - |
문제
나는 Java에서 쉽게 할 수있는 C#에서 무언가를 성취하려고 노력하고 있습니다. 그러나 약간의 문제가 있습니다. 정의되지 않은 수의 배열 객체는 Type 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을 컴파일해야합니다.
해결책
여기서 문제는 C#이 지원하지 않는다는 것입니다 공동 분산 (적어도 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.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) };
}
}
나는 당신이 시도했다고 생각합니다
list.AddRange((I[])arrayOfA);
이미?
편집하다 내 제안이 효과가 없다고 말하는 귀하의 의견에 대한 답변으로 : 1 분 전에이 코드를 성공적으로 실행했습니다.
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") };
}
}
}
아니면 그냥 요구 사항을 고려 했습니까?
일반적인 제약 조건을 추가하십시오
여기서 t : i
여기서 문제는 제네릭이 T를 구현한다는 것을 인식하지 못한다는 것입니다.
또한 루프 용을 수행하고 AddRange를 사용하는 대신 T 객체를 한 번에 하나씩 추가 할 수 있습니다.
C#의 유형 구조는 현재 이것을 지원하지 않습니다 (치료 Foo<T>
A로 Foo<I>
x : i) 이것은 I에서 공분산이라고합니다.
기본 프레임 워크는 그리고 C# 4.0은 지원을 추가하고 있습니다
이러한 명백한 캐스트가 필요하기 때문에 Marc의 대답이 가장 간단합니다.
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();
참조 객체의 배열은 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();
}