يجب أن تعلن باستخدام أساليب الزائدة أو المعلمات الاختيارية في C# 4.0?

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

سؤال

كنت أشاهد أندرس' الحديث عن C# 4.0 و معاينة التسلل من C# 5.0, مما جعلني أفكر عندما المعلمات الاختيارية المتاحة في C# ماذا ستكون الطريقة الموصى بها أن تعلن الطرق التي لا تحتاج جميع المعلمات المحددة لذلك.

على سبيل المثال شيء من هذا القبيل FileStream فئة لديها حوالي خمسة عشر المنشئات المختلفة والتي يمكن تقسيمها إلى المنطقية 'أسر' مثلا ، تلك أدناه من سلسلة ، هم من IntPtr و هم من SafeFileHandle.

FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);

يبدو لي أن هذا النوع من نمط يمكن تبسيطها من خلال وجود ثلاث منشئات بدلا من استخدام المعلمات الاختيارية عن تلك التي يمكن أن تكون المتعثرة ، والتي من شأنها أن تجعل عائلات مختلفة من منشئات أكثر وضوحا [ملاحظة:أعرف أن هذا التغيير لن يكون في BCL, أنا أتكلم نظريا لهذا النوع من الوضع].

ماذا تعتقد ؟ من C# 4.0 سوف تجعل أكثر منطقية لجعل ارتباطا وثيقا مجموعات من المنشئات الأساليب أسلوب واحد مع المعلمات الاختيارية ، أم أن هناك سبب وجيه التمسك التقليدية العديد من الزائد الآلية ؟

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

المحلول

أود أن تنظر في ما يلي:

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

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

نصائح أخرى

عند الزائد طريقة عادة ينفذ نفس الشيء مع عدد مختلف من الحجج فسيتم استخدام الإعدادات الافتراضية.

عند ينفذ الزائد طريقة وظيفة مختلف استنادا معالمها ثم الحمولة الزائدة سوف تستمر في استخدامها.

وكنت اختياري مرة أخرى في أيام VB6 بلدي ومنذ ذلك الحين غاب عن ذلك، وسوف تقلل الكثير من تعليق XML الازدواجية في C #.

ولقد تم استخدام دلفي، مع المعلمات الاختيارية، إلى الأبد. لقد تحولت إلى استخدام الزائدة بدلا من ذلك.

ولأنه عندما تذهب لخلق المزيد من الزائدة، فسوف confict دائما مع شكل المعلمة اختياري. وعليك بعد ذلك لتحويلها إلى غير اختياري على أي حال.

وأنا أحب فكرة أن هناك عادة واحدة <م> سوبر طريقة، والباقي هي مغلفة أبسط حول أن واحدا.

وأنا سوف بالتأكيد أن استخدام ميزة المعلمات الاختيارية من 4.0. يتخلص من السخرية ...

public void M1( string foo, string bar )
{
   // do that thang
}

public void M1( string foo )
{
  M1( foo, "bar default" ); // I have always hated this line of code specifically
}

... ويضع قيم الحق حيث كان الطالب يمكن أن نراهم ...

public void M1( string foo, string bar = "bar default" )
{
   // do that thang
}

وأكثر من ذلك بكثير بسيطة وأقل بكثير عرضة للخطأ. رأيت هذا في الواقع بوصفها علة في حالة الحمل الزائد ...

public void M1( string foo )
{
   M2( foo, "bar default" );  // oops!  I meant M1!
}

وأنا لم ألعب مع المطيع 4.0 بعد، ولكن لن أكون بالصدمة لمعرفة أن المطيع ببساطة تنبعث الزائدة بالنسبة لك.

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

وثمة نتيجة هامة من ربط المعلمات الاختيارية في الموقع المكالمة أنه سيتم تعيين القيم بناء على نسخة من قانون الهدف الذي يتوفر للمترجم. إذا كان Foo التجمع لديه Boo(int) الأسلوب مع القيمة الافتراضية من 5، والتجمع Bar يحتوي على الدعوة إلى Foo.Boo()، فإن المترجم معالجة أنه نتيجة لFoo.Boo(5). إذا تم تغيير القيمة الافتراضية إلى 6 ومعاد Foo التجمع، وسوف تستمر Bar للاتصال Foo.Boo(5) ما لم أو حتى معاد مع هذا الإصدار الجديد من Foo. وبالتالي ينبغي للمرء تجنب استخدام المعلمات الاختيارية عن الأشياء التي قد تتغير.

وأنا أتطلع إلى المعلمات الاختيارية لأنها تحافظ على ما هي الافتراضات أقرب إلى الأسلوب. وذلك بدلا من العشرات من خطوط لالزائدة التي تدعو مجرد طريقة "موسع"، عليك فقط تحديد طريقة واحدة ويمكنك ان ترى ما الافتراضي المعلمات الاختيارية لفي توقيع الأسلوب. فما استقاموا لكم فاستقيموا بدلا ننظر:

public Rectangle (Point start = Point.Zero, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

وبدلا من هذا:

public Rectangle (Point start, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

public Rectangle (int width, int height) :
    this (Point.Zero, width, height)
{
}

ومن الواضح أن هذا المثال بسيط حقا ولكن الحال في OP مع 5 الزائدة، ويمكن الحصول على أشياء سريعة الحقيقية المزدحمة.

ويمكن القول ما إذا كانت الوسائط الاختيارية أو الزائدة يجب أن تستخدم أو لا، ولكن الأهم من ذلك، ولكل ومنطقتهم حيث أنها لا يمكن الاستغناء عنه.

والوسائط الاختيارية، عندما تستخدم بالاقتران مع الوسائط المسماة، هي مفيدة للغاية عندما جنبا إلى جنب مع بعض منذ فترة طويلة حجة القوائم مع جميع اخليارات من المكالمات COM.

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

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

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

أخيرا وليس آخرا, إذا كنت المستهلك من API قد لا يكون لديك خيار فحص تفاصيل التنفيذ (إذا لم يكن لديك رمز المصدر) وبالتالي يكون هناك فرصة لرؤية إلى أي سوبر طريقة زائد هي التفاف.وهكذا كنت عالقا مع القراءة الطبيب على أمل أن جميع القيم الافتراضية المذكورة هناك ، ولكن هذا ليس هو الحال دائما.

بالطبع ليس هذا هو الجواب الذي يعالج جميع الجوانب ، ولكن أعتقد أنه يضيف واحد التي لم يتم تغطيتها حتى الآن.

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

رمز الأولية

public string HandleError(string message, bool silent=true, bool isCritical=true)
{
  ...
}

نفترض أن هذا هو واحد من العديد من المتصلين من الطريقة المذكورة أعلاه:

HandleError("Disk is full", false);

هنا الحدث ليست صامتة و هو تعامل الحرجة.

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

بعد ريفاكتور

السابق الدعوة لا تزال تجمع ولنفترض انه ينزلق من خلال ريفاكتور دون تغيير:

public string HandleError(string message, /*bool silent=true,*/ bool isCritical=true)
{
  ...
}

...

// Some other distant code file:
HandleError("Disk is full", false);

الآن false سيكون لها أثر غير مقصود ، الحدث لن يكون تعامل على أنها حرجة.

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

علما أن هناك أشكالا عديدة من نفس هذه المشكلة.واحد شكل آخر هو موضح هنا.

نلاحظ أيضا أن بدقة باستخدام المعلمات المسماة عند استدعاء الأسلوب سوف تجنب هذه المسألة ، مثل مثل هذا: HandleError("Disk is full", silent:false).ومع ذلك ، فإنه ليس من العملي أن نفترض أن جميع المطورين الآخرين (أو المستخدمين من العام API) سوف تفعل ذلك.

لهذه الأسباب أنا سوف تجنب استخدام معلمات اختيارية في API العامة (أو حتى العام الأسلوب إذا كان يمكن أن تستخدم على نطاق واسع) ما لم تكن هناك أخرى مقنعة الاعتبارات.

وكلا المعلمة الاختيارية، طريقة الزائد يكون هناك ميزة خاصة أو disadvantage.it تعتمد على تفضيل لاختيار بينهما.

ومعلمة اختيارية: متوفر فقط في صافي 4.0. المعلمة الاختيارية تقليل حجم التعليمات البرمجية. لا يمكن تعريف بها والمعلمة المرجع

وأساليب مثقلة: يمكنك تحديد خارج والمعلمات المرجع. سوف رمز حجم زيادة ولكن طريقة طاقتها هم من السهل أن نفهم.

في كثير من الحالات معلمات اختيارية تستخدم للتبديل التنفيذ.على سبيل المثال:

decimal GetPrice(string productName, decimal discountPercentage = 0)
{

    decimal basePrice = CalculateBasePrice(productName);

    if (discountPercentage > 0)
        return basePrice * (1 - discountPercentage / 100);
    else
        return basePrice;
}

خصم المعلمة هنا يستخدم لتغذية if-then-else.هناك تعدد الأشكال التي لم يكن معترف بها ، ومن ثم تم تنفيذها if-then-else.في مثل هذه الحالات فمن الأفضل بكثير أن تقسيم اثنين من التحكم في التدفقات إلى قسمين مستقلين طرق:

decimal GetPrice(string productName)
{
    decimal basePrice = CalculateBasePrice(productName);
    return basePrice;
}

decimal GetPrice(string productName, decimal discountPercentage)
{

    if (discountPercentage <= 0)
        throw new ArgumentException();

    decimal basePrice = GetPrice(productName);

    decimal discountedPrice = basePrice * (1 - discountPercentage / 100);

    return discountedPrice;

}

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

في مثل هذه الحالات ، أنا أفضل أن لا يكون المعلمات الاختيارية ، ولكن القوة المتصل صراحة حدد تنفيذ السيناريو الذي يناسب الوضع الحالي.

الوضع مشابه جدا إلى وجود المعلمات التي يمكن أن تكون فارغة.التي هي على قدم المساواة فكرة سيئة عند تنفيذ يغلي إلى البيانات مثل if (x == null).

يمكنك العثور على تحليل مفصل على هذه الروابط: تجنب المعلمات الاختيارية و تجنب Null المعلمات

وبينما هم (المفترض؟) بطريقتين أي ما يعادل من الناحية النظرية متاح لك لنموذج API الخاص بك من الصفر، لديهم للأسف بعض فرق دقيق عندما تحتاج إلى النظر في وقت التوافق للعملاء القديم الخاص بك في البرية. زميلي (بفضل برنت!) وأشار لي إلى هذا <وأ href = "http://haacked.com/archive/2010/08/10/versioning-issues-with-optional-arguments.aspx/" يختلط = "نوفولو" > آخر رائع: الإصدار القضايا مع الوسائط الاختيارية . بعض اقتبس منه:

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

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

لإضافة عدم التفكير عند استخدام الزائد بدلا من اخليارات:

وكلما كان لديك عدد من المعلمات التي تجعل فقط الشعور معا، لا يعرض اخليارات عليها.

وأو أكثر عموما، كلما تمكن التوقيعات طريقتك أنماط الاستخدام التي لا معنى لها، وتقييد عدد التباديل المكالمات ممكنة. على سبيل المثال، باستخدام الزائدة بدلا من اخليارات. (يحمل هذا الحكم ينطبق أيضا عندما يكون لديك العديد من المعلمات من نفس نوع البيانات، بالمناسبة، هنا، مثل أجهزة أساليب مصنع أو أنواع بيانات مخصصة يمكن أن تساعد)

مثال:

enum Match {
    Regex,
    Wildcard,
    ContainsString,
}

// Don't: This way, Enumerate() can be called in a way
//         which does not make sense:
IEnumerable<string> Enumerate(string searchPattern = null,
                              Match match = Match.Regex,
                              SearchOption searchOption = SearchOption.TopDirectoryOnly);

// Better: Provide only overloads which cannot be mis-used:
IEnumerable<string> Enumerate(SearchOption searchOption = SearchOption.TopDirectoryOnly);
IEnumerable<string> Enumerate(string searchPattern, Match match,
                              SearchOption searchOption = SearchOption.TopDirectoryOnly);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top