سؤال

مرحبا لنفترض أن هذه الأساليب 2:

private List<IObjectProvider> GetProviderForType(Type type)
        {
            List<IObjectProvider> returnValue = new List<IObjectProvider>();

            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
            {
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))
                {
                    returnValue.Add(provider.Value);
                }
            }
            return returnValue;
        }

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
        {
            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))

                    yield return provider.Value;              
        }

واحد الذي هو أسرع ؟ عندما ننظر في الطريقة الأولى ، أرى أن يتم تخصيص الذاكرة القائمة ، بما في رأيي أنه ليس هناك حاجة.على IEnumerable يبدو أن طريقة تكون أسرع مني.

على سبيل المثال, افترض أنك الدعوة

int a = GetProviderForType(myType).Count;
int b = GetProviderForType1(myType).Count();

الآن مسألة أخرى هناك الفارق في الأداء بين هذه 2 أعلاه ؟

ماذا تعتقد ؟

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

المحلول

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

إذا كنت في حاجة إلى استخدام النتائج مرة أخرى لأي سبب من الأسباب ، List<T> شكل سيكون أكثر كفاءة.

نلاحظ أن كلا من Count() طريقة التمديد ، Count الخاصية سوف تكون فعالة List<T> وتنفيذ Count() التحقق لمعرفة ما إذا كان الهدف تسلسل تنفذ ICollection<T> و يستخدم Count مكان الإقامة إذا كان الأمر كذلك.

وثمة خيار آخر وهو ما يجب أن يكون حتى المزيد كفاءة (على الرغم من أن فقط) سيكون استدعاء الزائد Count الذي يأخذ أحد المندوبين:

private int GetProviderCount(Type type)
{
  return _objectProviders.Count(provider =>
      (provider.Key.IsAssignableFrom(type) 
       || type.IsAssignableFrom(provider.Key))
      && provider.Value.SupportsType(type));
}

هذا سوف تجنب مستوى إضافي من indirections التي تكبدتها Where و Select البنود.

(كما يقول مارك ، على كميات صغيرة من البيانات الأداء الخلافات ربما تكون ضئيلة على أي حال.)

نصائح أخرى

دقة الإجابة على أسئلة من هذا القبيل يمكن أن تختلف اعتمادا على الكثير من العوامل, و قد تتغير كذلك CLR تتطور.السبيل الوحيد للتأكد هو قياس ذلك - و نضع في اعتبارنا أنه إذا كان الفرق صغير مقارنة هذه العملية سوف تظهر في, ثم يجب عليك اختيار أكثر قابلية للقراءة ، للصيانة طريقة الكتابة.

وعلى تلك المذكرة ، قد ترغب أيضا في محاولة:

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
{
    return _objectProviders.Where(provider => 
                  provider.Key.IsAssignableFrom(type) ||
                  type.IsAssignableFrom(provider.Key)) &&
                  provider.Value.SupportsType(type))
                           .Select(p => p.Value);
}

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

جزء مهم من هذا السؤال هو "ما هو حجم البيانات"?كيف العديد من الصفوف...

للحصول على كميات صغيرة من البيانات ، قائمة على ما يرام - وسوف يستغرق ضئيلة الوقت لتخصيص كبيرة بما يكفي قائمة ولن تغيير حجم عدة مرات (لا شيء, إذا يمكن أن أقول لكم كيف كبيرة أن يكون مقدما).

ولكن هذا لا مقياس كميات البيانات الضخمة;يبدو من غير المحتمل أن مزود الخدمة الخاص بك يدعم الآلاف من واجهات لذا لن أقول أنه هو ضروري للذهاب إلى هذا النموذج - ولكن ذلك لن يضر بشكل كبير.

بالطبع يمكنك استخدام LINQ أيضا:

return from provider in _objectProviders
       where provider.Key.IsAssignableFrom(type) ...
       select provider.Value;

وهذا هو أيضا المؤجلة yield نهج تحت الأغطية...

الفرق الرئيسي بين IEnumerable IList:

IEnumerable:تنفذ MoveNext,تعيين,على الأساليب الحالية والعودة نوع من IEnumerator تكرار من خلال السجلات.

IList :يعرض واجهة IEnumerable وكذلك هو أيضا مجموعة من غير عامة الكائنات التي يمكن الوصول إليها من خلال مؤشر حتى IEnumerable+ICollection(معالجة البيانات) و إضافة وإزالة إدراج(في مؤشر محددة) هي الأساليب المفيدة التي تنفذها IList.

بعد النظر في التعليمات البرمجية الخاصة بك في رأيي IEnumerable هو أكثر كفاءة ولكن عودته القائمة هو أيضا مفيدة إذا كنت تريد أن تفعل بعض التلاعب مع البيانات إذا كنت تريد فقط من خلال تكرار البيانات ثم IEnumerable هو الأفضل.

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