سؤال

لدي فئة C# التي تحتاج إلى معالجة سلسلة من العناصر (IEnumerable<T>) عبر مجموعة من الطرق ، لذلك لا يمكنني ببساطة foreach داخل طريقة. أنا أتصل .GetEnumerator() وتمرير هذا IEnumerator<T> حوله ويعمل بشكل رائع ، مما يمنحني المرونة التي أحتاجها أثناء التسلسل من خلال تسلسل واحد.

الآن أريد أن أسمح للآخرين بإضافة المنطق إلى هذه العملية. الطريقة الأكثر طبيعية للقيام بذلك هي منحهم واجهة مع طريقة تقبل IEnumerator<T>. من السهل ، القيام به ، وهو يعمل.

لكنني قلق من أن هذا أمر مضاد. عليهم أن يعرفوا أن IEnumerator<T> كان بالفعل .MoveNext() يسمى ، حتى يتمكنوا من الوصول ببساطة .Current. بالإضافة إلى أنني لا أرى أي سابقة لاستخدامها IEnumerator<T> في واجهات ليتم تنفيذها.

  1. ما المزالق التي لا أفكر فيها؟
  2. هل هناك نمط آخر يسمح لي بهذا الشيء فعالة آلية (أي لا أريد إنشاء/تدمير نسخ متعددة) دون تعريض IEnumerator<T> بحد ذاتها؟

تحديث: كما ذكرت في تعليق أدناه: ما أريده هو نوع من العام Stream<T>. يجب أن أكون قادرًا على رؤية العنصر التالي بفعالية (IEnumerator.Current -> .Peek()) وتستهلكها (IEnumerator<T>.MoveNext() -> .Pop()).

إستعملت IEnumerator<T> لأنها تناسب واجهة الفاتورة. أفضل استخدام أنواع BCL الشائعة عندما تكون مناسبة ، لكن يبدو أنني كنت أسيء استخدام هذا.

لذلك السؤال 3) هل هناك فئة تناسب هذه الحاجة؟ أو يجب أن أقوم فقط بإنشاء دفق خاص بي والذي ينفذ بتكاسل IEnumerator<T> داخليا؟ ثم سيكون مغلف تماما. أرغب في عدم استخدام العديد من المجموعات الحالية لأنها لديها سعة تخزين داخلية ، في حين أود أن تكون التخزين IEnumerable<T> iteslf.


حسنًا ، يبدو أن الإجماع IEnumerator<T> في كثير من الأحيان يجري ValueType وكذلك عدم معرفة ما قبل حالة IEnumerator<T>, ، أنها فكرة سيئة بشكل عام لتمريرها.

أفضل اقتراح سمعته هو إنشاء صفي الخاص الذي يتم تمريره. أي اقتراحات أخرى؟

هل كانت مفيدة؟

المحلول

إذا فهمت هذا بشكل صحيح ، لديك عدد من الطرق التي يمكنها جميعًا استدعاء Movenext على التسلسل وتريد أن تتعاون هذه الأساليب مع بعضها البعض ، لذلك تتجول IEnumerator<T>. هناك بالتأكيد بعض الاقتران الضيق هنا ، كما ذكرت ، لأنك تتوقع أن يكون العداد في حالة معينة عند مدخل كل طريقة. يبدو أن ما أنت عليه حقًا هنا هو شيء مثل فئة الدفق ، وهو مجموعة (نوع من) و Iterator (له فكرة عن الموقع الحالي). أود أن أله تكرارك وأي حالة أخرى تحتاجها في صفك ولديها الأساليب المختلفة كأعضاء في هذا الفصل

نصائح أخرى

يجب بالتااكيد لا تمر IEnumerator<T> حول. بصرف النظر عن أي شيء آخر ، يمكن أن يكون لديه البعض جداً آثار غريبة في بعض الحالات. ماذا تتوقع أن يحدث هنا ، على سبيل المثال؟

using System;
using System.Collections.Generic;

class Test
{
    static void ShowCurrentAndNext(IEnumerator<int> iterator)        
    {
        Console.WriteLine("ShowCurrentAndNext");
        Console.WriteLine(iterator.Current);
        iterator.MoveNext(); // Let's assume it returns true
        Console.WriteLine(iterator.Current);
    }

    static void Main()
    {
        List<int> list = new List<int> { 1, 2, 3, 4, 5 };
        using (var iterator = list.GetEnumerator())
        {
            iterator.MoveNext(); // Get things going
            ShowCurrentAndNext(iterator);
            ShowCurrentAndNext(iterator);
            ShowCurrentAndNext(iterator);
        }
    }
}

بعض التغييرات لمحاولة:

using (List<int>.Enumerator iterator = list.GetEnumerator())

و

using (IEnumerator<int> iterator = list.GetEnumerator())

حاول التنبؤ بالنتائج في كل حالة :)

من المسلم به الآن أن هذا مثال شرير بشكل خاص ، لكنه يدل على بعض حالات الزاوية المرتبطة بالتمرير حول الحالة القابلة للتغيير. أود أن أشجعك بشدة على أداء كل تكرارك في طريقة "مركزية" تستدعي الطرق الأخرى المناسبة فقط مع القيمة الحالية.

أنصح بقوة بعدم تمرير العداد نفسه ؛ ما السبب الذي لديك لهذا الغرض ، بصرف النظر عن الحاجة إلى القيمة الحالية؟

ما لم أكن أفتقد شيئًا واضحًا ، أوصي بوظائف الأداة المساعدة الخاصة بك ببساطة تأخذ النوع الذي تعدده كمعلمة ، ثم لديك خارجي واحد foreach حلقة تعالج التعداد الفعلي.

ربما يمكنك تقديم بعض المعلومات الإضافية حول سبب اتخاذ قرار التصميم هذا حتى الآن.

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

قد ترغب أيضًا في النظر إلى الإطار التفاعلي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top