تحويل مجموعة من نوع T إلى مجموعة من النوع الأول حيث T تنفذ أنا في C #

StackOverflow https://stackoverflow.com/questions/1006746

  •  06-07-2019
  •  | 
  •  

سؤال

واني اسعى الى تحقيق شيء في C # أن أفعل بسهولة في جاوة. ولكن وجود بعض المتاعب. لدي عدد غير محدد من صفائف الكائنات من النوع T. وتنفذ واجهة I. أحتاج إلى مجموعة من أنا في نهاية هذا هو مجموع كل القيم من كل المصفوفات. لا نتحمل أية صفائف سوف تحتوي على نفس القيم.

وهذا الرمز جافا يعمل.

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 # لا يدعم <لأ href = "http://weblogs.asp.net/astopford/archive/2006/12/28/c-generics-covariance.aspx" يختلط = "نوفولو noreferrer "> التغاير (على الأقل ليس حتى 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();

لأحد أن strumbles عبر هذا السؤال وتستخدم الصافي 3.5، وهذا هو وسيلة أكثر إحكاما قليلا من فعل الشيء نفسه، وذلك باستخدام ينق.

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

وبالفعل؟

تعديل في الرد على تعليقك قائلا إن اقتراحي لن تنجح: I بنجاح ركض هذا الرمز قبل دقيقة واحدة فقط:

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 تنفذ I. قد عمل ليعلن صراحة T: I.

وأيضا يمكن أن تفعله لحلقة وإضافة الخاصة بك T الكائنات في وقت واحد بدلا من استخدام AddRange.

وهيكل نوع ج # لا يدعم حاليا هذا (علاج Foo<T> باعتباره Foo<I> إذا X: I). هذا هو ما يسمى التغاير على I

والإطار الأساسي لا، و ج # 4.0 هو إضافة دعم لذلك

وولهذا يلزم توفير يلقي صريحة، والإجابة مارك لكونها أبسط.

في الخاص C # الرمز الذي لم يتم إضافة arrayOfA إلى قائمة نتيجة:

List<I> list = new List<I>();
foreach (T[] arrayOfA in arrays)
    list.AddRange(arrayOfA);

return list.ToArray();

ومع ذلك، إذا كنت تستخدم الصافي 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();

<وأ href = "http://blogs.msdn.com/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx" يختلط = "نوفولو noreferrer"> صالحة للكائنات المرجعية هي التغاير في C # (وينطبق الشيء نفسه للجافا).

ومن اسم، وأعتقد بأن ما تتمتعون به 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