c# - ienumerable شرح




IEnumerable مقابل قائمة-ما لاستخدام؟ كيف يعملون؟ (6)

لدي بعض الشكوك حول كيفية عمل الباحثين ، و LINQ. خذ بعين الاعتبار هذين الاختيارين البسيطين:

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

أو

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

لقد غيرت أسماء الكائنات الأصلية بحيث يبدو هذا كمثال أكثر عمومية. الاستعلام نفسه ليس بتلك الأهمية. ما أريد أن أسأله هو:

foreach (Animal animal in sel) { /*do stuff*/ }
  1. لقد لاحظت أنه في حالة استخدام IEnumerable ، عندما أقوم بالتصحيح وفحص "sel" ، والذي في هذه الحالة هو IEnumerable ، فإنه يحتوي على بعض أعضاء مثيرة للاهتمام: "الداخلي" ، "الخارجي" ، "innerKeySelector" و "outerKeySelector" ، هذه الأخيرة 2 يبدو أن المندوبين. ليس لدى العضو "الداخلي" مثيلات "الحيوان" في ذلك ، ولكن بالأحرى مثيلات "الأنواع" ، التي كانت غريبة جداً بالنسبة لي. يحتوي العضو "الخارجي" على مثيلات "Animal". أفترض أن اثنين من المندوبين تحديد الذي يدخل وما يخرج منه؟

  2. لاحظت أنه إذا كنت تستخدم "متميز" ، فإن "الداخلي" يحتوي على 6 عناصر (وهذا غير صحيح لأن 2 فقط هي مميزة) ، ولكن "الخارجية" تحتوي على القيم الصحيحة. مرة أخرى ، ربما تحدد الأساليب المفوضة هذا ولكن هذا أكثر قليلاً مما أعرفه عن IEnumerable.

  3. الأهم من ذلك ، أي من الخيارين هو أفضل أداء؟

تحويل قائمة الشر عبر .ToList() ؟

أو ربما استخدام العداد مباشرة؟

إذا كنت تستطيع ، يرجى أيضا شرح بعض الشيء أو رمي بعض الروابط التي توضح هذا الاستخدام من IEnumerable.


أهم شيء هو إدراك أنه ، باستخدام Linq ، لا يتم تقييم الاستعلام على الفور. يتم تشغيله فقط كجزء من التكرار خلال IEnumerable<T> الناتجة في foreach - هذا ما يفعله جميع المندوبين الغريبين.

لذلك ، يقوم المثال الأول بتقييم الاستعلام على الفور من خلال استدعاء ToList ووضع نتائج الاستعلام في قائمة.
المثال الثاني بإرجاع IEnumerable<T> يحتوي على كافة المعلومات المطلوبة لتشغيل الاستعلام فيما بعد.

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


إذا كان كل ما تريد القيام به هو تعدادهم ، استخدم IEnumerable .

ومع ذلك ، كن حذرًا أن تغيير المجموعة الأصلية التي يتم تعدادها عملية خطيرة - في هذه الحالة ، ستحتاج إلى ToList أولاً. سيؤدي ذلك إلى إنشاء عنصر قائمة جديد لكل عنصر في الذاكرة ، تعداد IEnumerable وهو بالتالي أقل أداء إذا قمت بالتعداد مرة واحدة فقط - ولكن أكثر أمانًا وأحيانًا تكون أساليب List مفيدة (على سبيل المثال في الوصول العشوائي).


بالإضافة إلى جميع الإجابات المنشورة أعلاه ، هنا هو سنتي. هناك العديد من الأنواع الأخرى غير القائمة التي تنفذ IEnumerable مثل ICollection و ArrayList إلخ. إذا كان لدينا IEnumerable كمعلمة لأي طريقة ، يمكننا تمرير أي نوع من أنواع المجموعات إلى الوظيفة. أي يمكن أن يكون لدينا طريقة للعمل على التجريد وليس أي تنفيذ محدد.


تتمثل ميزة IEnumerable في التنفيذ المؤجل (عادةً مع قواعد البيانات). لن يتم تنفيذ الاستعلام حتى تتتكرر خلال البيانات. إنه استعلام ينتظر حتى الحاجة إليه (ويعرف أيضًا باسم التحميل البطيء).

إذا قمت بالاتصال ToList ، سيتم تنفيذ الاستعلام ، أو "تتحقق" كما أحب أن أقول.

الاثنين لهم ايجابيات وسلبيات. إذا قمت بالاتصال بـ ToList ، فيمكنك إزالة بعض الغموض حول وقت تنفيذ الاستعلام. إذا كنت تلتزم بـ IEnumerable ، فستحصل على ميزة أن البرنامج لا يقوم بأي عمل حتى يكون مطلوبًا بالفعل.


لم يذكر أحد أحد الاختلافات الحاسمة ، حيث أجاب بسخرية على سؤال مغلق باعتباره نسخة مكررة من هذا.

IEnumerable للقراءة فقط والقائمة ليست كذلك.

انظر الفرق العملي بين القائمة و IEnumerable






ienumerable