سؤال

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

public int GetValue(); 

أو:

public void GetValue(out int x);

أنا لا أفهم حقا الخلافات بينهما, لذلك لا أعرف أيهما أفضل.هل يمكنك أن تشرح لي هذا ؟

شكرا لك.

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

المحلول

والقيم العودة تكاد تكون <م> دائما الخيار الصحيح عندما لا يكون أسلوب أي شيء آخر للعودة. (في الواقع، لا أستطيع التفكير في أي الحالات التي كنت من أي وقت مضى تريد طريقة الفراغ مع معلمة out، إذا كان لي الاختيار. C # 7 في أساليب Deconstruct لالتفكيكية التي تدعمها لغة كعامل استثناء جدا، نادرة جدا لهذه القاعدة.)

وبصرف النظر عن أي شيء آخر، فإنه يتوقف المتصل من الحاجة إلى تعريف متغير على حدة:

int foo;
GetValue(out foo);

ومقابل

int foo = GetValue();

وخارج القيم أيضا منع طريقة تسلسل مثل هذا:

Console.WriteLine(GetValue().ToString("g"));

و(في الواقع، وهذا هو واحد من المشاكل مع واضعي الملكية أيضا، وذلك هو السبب يستخدم نمط البناء الأساليب التي تعيد البناء، على سبيل المثال myStringBuilder.Append(xxx).Append(yyy)).

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

عودة القيم FTW.

وتحرير: من حيث ما يحدث ...

وأساسا عند تمرير في حجة لمعلمة "خارج"، وكنت <م> هل لديك لتمرير في متغير. (تصنف عناصر صفيف كمتغيرات أيضا.) طريقة استدعاء لايوجد متغير "الجديد" على كومة من أجل المعلمة - ويستخدم المتغير الخاص للتخزين. أي تغييرات في متغير واضحة على الفور. وفيما يلي مثال يوضح الفرق:

using System;

class Test
{
    static int value;

    static void ShowValue(string description)
    {
        Console.WriteLine(description + value);
    }

    static void Main()
    {
        Console.WriteLine("Return value test...");
        value = 5;
        value = ReturnValue();
        ShowValue("Value after ReturnValue(): ");

        value = 5;
        Console.WriteLine("Out parameter test...");
        OutParameter(out value);
        ShowValue("Value after OutParameter(): ");
    }

    static int ReturnValue()
    {
        ShowValue("ReturnValue (pre): ");
        int tmp = 10;
        ShowValue("ReturnValue (post): ");
        return tmp;
    }

    static void OutParameter(out int tmp)
    {
        ShowValue("OutParameter (pre): ");
        tmp = 10;
        ShowValue("OutParameter (post): ");
    }
}

والنتائج:

Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10

والفرق هو في "ما بعد" خطوة - أي بعد أن تم تغيير المتغير المحلي أو المعلمة. في اختبار ReturnValue، وهذا لا فرق لمتغير value ثابت. في اختبار OutParameter، يتم تغيير متغير value من قبل tmp = 10; خط

نصائح أخرى

ما هو أفضل ، يعتمد على الوضع الخاص بك. واحد من الأسباب out موجود هو تسهيل عودة قيم متعددة من استدعاء الأسلوب:

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}

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

تحرير: هذه عينة مما يدل على واحد من الأسباب التي الكلمة موجودا.المذكورة أعلاه لا تعتبر أفضل الممارسات.

يجب عليك عموما تفضل قيمة العائد على الخروج المعلمة.خارج params هي neccissary الشر إذا كنت تجد نفسك في كتابة التعليمات البرمجية التي تحتاج إلى القيام به 2 الأشياء.وخير مثال على ذلك هو محاولة نمط (مثل Int32.TryParse).

دعونا النظر في ما المتصل من الطريقتين سوف تضطر إلى القيام به.لأول سبيل المثال أستطيع أن أكتب هذا...

int foo = GetValue();

لاحظ أنه لا يمكن تعريف متغير تعيين ذلك عن طريق الأسلوب الخاص بك في خط واحد.على سبيل المثال 2 يبدو مثل هذا...

int foo;
GetValue(out foo);

أنا مضطرة الآن أن تعلن بلدي متغير مقدما كتابة التعليمات البرمجية أكثر من سطرين.

التحديث

مكان جيد للبحث عند طرح هذه الأنواع من السؤال هو .NET Framework تصميم المبادئ التوجيهية.إذا كان لديك إصدار كتاب ثم يمكنك أن ترى شروح من قبل أندرس هيلسبرغ وغيرها على هذا الموضوع (الصفحة 184-185) ولكن النسخة الإلكترونية هو هنا...

http://msdn.microsoft.com/en-us/library/ms182131(مقابل.80).aspx

إذا كنت تجد نفسك بحاجة إلى العودة شيئين من API ثم التفاف عليها في البنية/الفصل سيكون أفضل من الخروج المعلمة.

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

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore

وبالطبع المتصل لا يزال يتجاهل قيمة <م> في المعلمة out، ولكن كنت قد لفتت الانتباه لذلك.

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

وانها تفضيل أساسا

وأنا أفضل العوائد وإذا كان لديك عوائد متعددة يمكنك التفاف عليها في النتيجة DTO

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

ويجب عليك دائما تقريبا استخدام قيمة الإرجاع. معلمات "out" خلق نوعا من الاحتكاك إلى الكثير من واجهات برمجة التطبيقات، compositionality، وما إلى ذلك.

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

هل يمكن أن يكون فقط قيمة الإرجاع واحدة في حين يمكن أن يكون متعددة من المعلمات.

وتحتاج فقط للنظر من المعلمات في تلك الحالات.

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

وأود أن تفضل التالية بدلا من أي من تلك الموجودة في هذا المثال البسيط.

public int Value
{
    get;
    private set;
}

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

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

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

وليس هناك فرق حقيقي، من المعلمات في C # السماح طريقة عودة أكثر من قيمة واحدة، أن يكون كل شيء.

ولكن هناك بعض الاختلافات الطفيفة، ولكن غير منهم من المهم حقا:

وسوف تستخدم من المعلمة فرض لك استخدام خطين مثل:

int n;
GetValue(n);

وأثناء استخدام قيمة الإرجاع سيتيح لك ان تفعل ذلك في سطر واحد:

int n = GetValue();

وثمة فرق آخر (الصحيح فقط لأنواع القيمة وفقط إذا C # لا يتمشى وظيفة) هو أن استخدام قيمة الإرجاع سيجعل بالضرورة نسخة من القيمة عند عودة وظيفة في حين باستخدام OUT المعلمة لن بالضرورة القيام بذلك.

وكما قال آخرون: قيمة الإرجاع، وليس من المعلمة

واسمحوا لي أن يوصي لك كتاب "المبادئ التوجيهية تصميم الإطار" (الطبعة 2ND)؟ صفحات 184-185 تغطية الأسباب لتجنب الخروج بارامس. والكتاب كله توجيه لكم في الاتجاه الصحيح على جميع أنواع القضايا الترميز .NET.

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

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

بالإضافة إلى ذلك, عودة القيم متوافقة مع غير متزامن تصميم النماذج.

لا يمكنك تعيين وظيفة "المتزامن" إذا كان يستخدم المرجع أو المعلمات.

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

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

var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}

ومقابل:

var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}

من هو أكثر فائدة عندما تحاول إرجاع الكائن الذي أعلن في الأسلوب.

مثال

public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}

قيمة الإرجاع هو القيمة التي تم إرجاعها بواسطة الأسلوب الخاص بك.

حيث بها المعلمة ، و المرجع 2 الكلمات الرئيسية من C# فهي تسمح لتمرير المتغيرات كما المرجعية.

الفرق كبير بين المرجع و بها هو ، المرجع يجب أن يكون initialised من قبل ، بها لا

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

وأعتقد أنه يناسب لغات البرمجة كائنية التوجه الأفضل للإجراءات ذات قيمة تعود على (VRPs) لتكون حتمية ونقية.

'VRP' هو اسم الأكاديمية الحديثة لدالة يسمى كجزء من التعبير، ولها قيمة الإرجاع الذي يحل محل نظريا هذه الدعوة خلال تقييم التعبير. مثلا في عبارة مثل x = 1 + f(y) وf وظيفة يقضي بأنه VRP.

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

و"بيور" يعني عدم وجود آثار جانبية: استدعاء الدالة لا يفعل شيئا <م> إلا حساب النتيجة. ويمكن تفسير هذا يعني لا <م> مهم آثار جانبية، من الناحية العملية، لذلك إذا كان VRP إخراج رسالة التصحيح في كل مرة يطلق عليه، على سبيل المثال، التي يمكن على الأرجح يمكن تجاهلها.

وهكذا، إذا، في C #، وظيفة ليست حتمية ونقية، وأنا أقول لك أن جعلها وظيفة void (وبعبارة أخرى، ليس VRP)، وينبغي أن تعاد أي قيمة يحتاجها للعودة في أي ل out أو معلمة ref.

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

وpublic void DeleteBasketItems(BasketItemCategory category, out int count);

إذا كنت تريد بعض الأحيان إلى استدعاء هذه الدالة ولكن لن تحصل على count، يمكنك دائما تعلن عن الحمولة الزائدة.

وقد ترغب في معرفة <م> لماذا برمجة هذه الدعاوى أسلوب جوه المنحى أفضل. على نطاق واسع، وتنسجم مع أسلوب البرمجة التي يمكن أن يكون (قليلا غير دقيق) يسمى "البرمجة الإجرائية، وأنه هو أسلوب البرمجة الإجرائي الذي يناسب البرمجة كائنية التوجه على نحو أفضل.

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

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

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

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