문제

나는 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();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top