لماذا لا تقوم صفائف C# متعددة الأبعاد بتطبيق IEnumerable<T>؟

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

سؤال

لقد لاحظت للتو أن المصفوفة متعددة الأبعاد في C# لا يتم تنفيذها IEnumerable<T>, ، بينما يتم تنفيذه IEnumerable.بالنسبة للمصفوفات أحادية البعد، كلاهما IEnumerable<T> و IEnumerable تنفذ.

لماذا هذا الاختلاف؟إذا كانت هناك مجموعة متعددة الأبعاد IEnumerable, ، بالتأكيد يجب عليه أيضًا تنفيذ الإصدار العام؟لقد لاحظت هذا لأنني حاولت استخدام طريقة تمديد على مصفوفة متعددة الأبعاد، والتي تفشل إلا إذا استخدمتها Cast<T> أو مشابه؛لذلك يمكنني بالتأكيد رؤية الحجة لتنفيذ المصفوفات متعددة الأبعاد IEnumerable<T>.

لتوضيح سؤالي في الكود، أتوقع طباعة الكود التالي true أربع مرات، في حين أنه يطبع فعلا true, false, true, true:

int[] singleDimensionArray = new int[10];
int[,] multiDimensional = new int[10, 10];

Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiDimensional is IEnumerable<int>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiDimensional is IEnumerable);
هل كانت مفيدة؟

المحلول

ووCLR لديها نوعين مختلفين من صفائف: <م> ناقلات الذي يضمن أن تكون ذات بعد واحد مع الحد السفلي من 0، وأكثر عمومية المصفوفات التي يمكن أن يكون غير صفر حدود ورتبة أخرى من 0.

ومن القسم 8.9.1 من المواصفات CLI:

<اقتباس فقرة>   

وبالإضافة إلى ذلك، تم إنشاؤها باستخدام ناقلات   نوع العنصر T، ينفذ   واجهه المستخدم   System.Collections.Generic.IList<U>   (§8.7)، حيث U: = T

وأنا يجب أن أقول أنه يبدو غريبا جدا بالنسبة لي. نظرا لأنها تنفذ بالفعل IEnumerable أنا لا أرى لماذا لا ينبغي أن تنفيذ IEnumerable<T>. فإنه لن جعل الكثير من الشعور لتنفيذ IList<T>، ولكن واجهة بسيطة العامة يكون على ما يرام.

إذا كنت تريد هذا، هل يمكن إما استدعاء Cast<T> (إذا كنت تستخدم الصافي 3.5) أو الكتابة أسلوب الخاصة بك لتكرار خلال مجموعة. لتجنب صب كنت قد لكتابة طريقتك الخاصة التي وجدت في الحدود الدنيا / العليا من كل البعد، وأشياء المنال بهذه الطريقة. ليس لطيفا بشكل رهيب.

نصائح أخرى

وهناك الحل: يمكنك تحويل أي مجموعة متعددة الأبعاد إلى IEnumerable

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this Array target)
    {
        foreach (var item in target)
            yield return (T)item;
    }
}

المصفوفات متعددة الأبعاد هي لا المصفوفات لغرض التسلسل الهرمي للميراث.إنهم نوع منفصل تمامًا.بالإضافة إلى ذلك، هذا النوع لا يحظى بدعم جيد من إطار العمل لسببين محتملين:

  • انها ليست حقا مفيدة.الاستخدام الحقيقي الوحيد للمصفوفات متعددة الأبعاد هو المصفوفات.بالنسبة لأي شيء آخر تقريبًا، فإن هياكل البيانات الأخرى (على سبيل المثال.صفائف خشنة) أكثر ملاءمة.
  • ليس من السهل ابتكار طرق عامة ومفيدة لهذه الهياكل.

في حالة IEnumerable, ، كيف ينبغي أن يتم تنفيذ ذلك، أي.في أي ترتيب ينبغي تعداد العناصر؟لا يوجد ترتيب متأصل في المصفوفات متعددة الأبعاد.

والصفر صفائف الأبعاد واحدة تطبق على حد سواء IEnumerable وIEnumerable<T>، ولكن المصفوفات متعددة الأبعاد، للأسف، تنفذ IEnumerable فقط. و"الحل البديل" من قبلJader دياس بالفعل تحويل مجموعة متعددة الأبعاد لIEnumerable<T> ولكن مع تكلفة ضخمة: سيتم محاصر كل عنصر من عناصر مجموعة

وهنا هو الإصدار الذي لن يسبب الملاكمة لكل عنصر:

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
    {
        foreach (var item in target)
            yield return item;
    }
}

وصفائف خشنة لا تدعم IEnumerable<int> سواء، لأن هياكل متعددة الأبعاد ليست حقا مجموعة من نوع، فهي مجموعة من مجموعة من نوع:

int[] singleDimensionArray = new int[10];
int[][] multiJagged = new int[10][];

Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiJagged is IEnumerable<int[]>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiJagged is IEnumerable);

ويطبع صحيح، صحيح، صحيح، صحيح.

ملاحظة : لint[,] ليست IEnumerable<int[]>، وهذا للأسباب المحددة في إجابة أخرى، وهي لا توجد طريقة عامة لمعرفة أي بعد تكرار انتهى. مع صفائف خشنة، وليس هناك مجالا كبيرا للتفسير كما أنه بناء الجملة واضح جدا عن كونها مجموعة من المصفوفات.

وفكر عكسيا. مجموعة 2D وموجود بالفعل. مجرد تعداد ذلك. إنشاء مجموعة 2D ومع درجة ومكان صفيف أو علامات أولية، بما في ذلك القيم المكررة.

int[] secondmarks = {20, 15, 31, 34, 35, 50, 40, 90, 99, 100, 20};

IEnumerable<int> finallist = secondmarks.OrderByDescending(c => c);

int[,] orderedMarks = new int[2, finallist.Count()];

Enumerable.Range(0, finallist.Count()).ToList().ForEach(k => {orderedMarks[0, k] = (int) finallist.Skip(k).Take(1).Average();
orderedMarks[1, k] = k + 1;}); 

Enumerable.Range(0, finallist.Count()).Select(m => new {Score = orderedMarks[0, m], Place = orderedMarks[1, m]}).Dump();

والنتائج:

Score Place

100     1
99      2 
90      3 
50      4 
40      5 
35      6    
34      7    
31      8    
20      9     
20     10 
15     11 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top