باستخدام الكلمات الرئيسية REFOR وإخراجها مع المرور بالرجوع إلى القيمة في C #

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

  •  18-09-2019
  •  | 
  •  

سؤال

هنا هو ما أفهمه حتى الآن:

تمرير القيمة

تمرير بالقيمة يعني نسخة من الحجة يتم تمريرها. التغييرات في تلك النسخة لا تغير الأصل.

تمر بالرجوع

تمر بالمرجع يعني مرجع إلى الأصل يتم تمريره. التغييرات في المرجع تؤثر على الأصل.

روجع الكلمة الرئيسية

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

خارج الكلمة

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

سؤال

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

مساعدة في تقدير كبير.

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

المحلول

انت ترغب أبدا يجمع ref و out في 1 المعلمة. كلاهما يعني "تمرير بالرجوع".

يمكنك بالطبع الجمع بين المعلمات المرجعية والمعلمات الخارجية بطريقة واحدة.

الفرق بين ref و out يكمن أساسا في نوايا. وبعد Reflue إشارات نقل البيانات 2-Way، out يعني 1 طريقة.

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

void SetOne(out int x) 
{
  int y = x + 1; // error, 'x' not definitely assigned.
  x = 1;         // mandatory to assign something
}

void AddTwo(ref int x)
{
    x = x + 2;  // OK, x  is known to be assigned
}

void Main()
{
    int foo, bar;

    SetOne(out foo); // OK, foo does not have to be assigned
    AddTwo(ref foo); // OK, foo assigned by SetOne
    AddTwo(ref bar); // error, bar is unassigned
}

نصائح أخرى

مساعدة في تقدير كبير

سيتم تحسين فهمك من خلال الاستخدام الصحيح والحريق للغة.

تمرير بالقيمة يعني نسخة من الحجة يتم تمريرها.

نعم، هذا دقيق تماما.

التغييرات في تلك النسخة لا تغير الأصل.

ليس تماما. تبدأ من خلال التمييز بعناية بين القيم و المتغيرات. وبعد انصح:

class Foo { public int x; }
...
void N() 
{
  Foo blah = new Foo();
  blah.x = 0;
  M(blah);
}
...
void M(Foo foo)
{
  foo.x = 123; // changes blah.x
  foo = null; // does not change blah
}

المتغيرات هنا هي x، blah و foo. X هو حقل، بلاه هو محلي، فو هو معلمة رسمية.

القيم هنا لاغية، 0، 123، ومرجع إلى مثيل فو. هذا المرجع هو قيمة. من الأهمية بمكان أن نفهم هذه الحقيقة.

يتم تمرير نسخة من قيمة blah عن طريق نسخ قيمة المتغير بلها إلى فو المتغير. قيمة BLAH هي إشارة إلى مثيل فو.

M يمكن أن يغير قيمة المتغير X لأن M لديه نسخة من قيمة BLAH، وهي مرجع إلى FOO. عندما يغير م محتويات FOO إلى NULL، لا يغير ذلك BLAH؛ يحتوي فو على نسخة من قيمة بلاه.

تمر بالمرجع يعني مرجع إلى الأصل يتم تمريره.

اختر صياغةك بعناية. ما هو "الأصلي"؟

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

التغييرات في المرجع تؤثر على الأصل.

نظرا لأن المعلمة والحجة هي الأسماء المستعارة لبعضها البعض، فليس هذا التغييرات في المرجع يؤثر على الأصل؛ المرجع هو الأصلي. كلاهما نفس المتغير.

يروي المرجع المترجم الذي يتم تهيئة الكائن قبل الدخول إلى الوظيفة.

"الكائن" لا معنى له. تقصد "المتغير".

"المرجع" لا "أخبر التحويل البرمجي أن المتغير يتم تهيئة". بدلا من ذلك، أخبر "المرجع" أن التحميل "أنت، مترجم، يجب التحقق من تهيئة المتغير". هذا مختلف تماما!

المرجع يعني أن القيمة محددة بالفعل،

لا، يتطلب المرجع عامل تم تعيين بالفعل. لا يوجد شيء مثل "تحديد قيمة".

لذلك يمكن أن تقرأ الطريقة وتعديلها.

حيث عن طريق "ذلك" تعني "المتغير".

المرجع هو طريقتان، سواء داخل وخارج.

صيح.

يخبر التحويل البرمجي أن الكائن سيكون على inialized داخل الوظيفة.

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

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

خارج يعني أن القيمة غير موجودة بالفعل،

مرة أخرى، عن طريق "القيمة"، تقصد "المتغير". ولكن هذا غير دقيق. من القانوني تماما اجتياز متغير تهيئة كمعلمة "خارج". لا طائل منه، ولكن القانونية.

وبالتالي يجب تعيين قبل الاتصال العودة.

"العودة" لا يسمى؛ يتم استدعاء الأساليب. ولكن نعم، يجب أن تقوم الطريقة بتعيين قيمة للمتغير قبل العودة بشكل طبيعي.

خارج هي طريقة واحدة فقط، والتي هي خارج.

حق.

إذا في أي سيناريوهات تجمع بين استخدام المرجع والخلف

لا توجد مثل هذه السيناريوهات.

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

  • ref int num لمعلمة داخل / خارج. الوظيفة مايو تعديل القيمة فيه.
  • out int num مثل المرجع باستثناء الوظيفة يجب تعيين قيمة لذلك قبل العودة.

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

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

يحرر: شرط واحد لأنواع المرجعية هي المعلمات ref StringBuilder word أو StringBuilder word (حسب القيمة) تتصرف بنفس الشيء - تتأثر السلسلة الخارجية، على الرغم من أن التنفيذ الأساسي قد يختلف قليلا لأنه في هذه النقطة، فإن التركيز هو المرجع وليس القيمة على كومة الكومة.

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

لا يمكنك استخدام "خارج" و "المرجع" معا. هناك ثلاث اتفاقيات مكالمات في C # (إطار صافي):

  • لا الكلمة الرئيسية = تمريرة حسب القيمة (في)
  • كلمة "خارج" = تمرير حسب المرجع (المرجع) مع عدم وجود متطلبات مهمة محددة قبل الاتصال
  • كلمة "المرجع" الرئيسية = تمرير حسب المرجع (المرجع) بمتطلبات مهمة محددة قبل الاتصال

C # لا يوجد لديه قدرة المعلمة الحقيقية أو الخروج.

لمعرفة أن المعلمات "خارج" في C # ليست معلمات صحيحة، يمكنك استخدام التعليمات البرمجية التالية:

  public class Test
  {
    Action _showValue;

    public void Run()
    {
      string local = "Initial";
      _showValue = () => { Console.WriteLine(local.ToString()); };

      Console.WriteLine("Passing by value");
      inMethod(local);

      Console.WriteLine("Passing by reference with 'out' keyword");
      outMethod(out local);

      Console.WriteLine("Passing by reference with 'ref' keyword");
      refMethod(ref local);

    }

    void inMethod(string arg)
    {
      _showValue();
      arg = "IN";
      _showValue();
    }

    void outMethod(out string arg)
    {
      _showValue();
      arg = "OUT";
      _showValue();
    }

    void refMethod(ref string arg)
    {
      _showValue();
      arg = "REF";
      _showValue();
    }
  }

الإخراج هو:

Passing by value
Initial
Initial
Passing by reference with 'out' keyword
Initial
OUT
Passing by reference with 'ref' keyword
OUT
REF

كما ترون، كلاهما "خارج" و "المرجع" يمر فعلا عن طريق المرجع. الفرق الوحيد هو في كيفية التعامل مع المترجم يعاملهم لأغراض مهمة محددة.

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

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

إذا فهمت C ++ ربما ستساعدك ذلك:

void Foo(Bar) {} // pass by value c# (if it's a value type ;))
void Foo(Bar) {} // c++

void Foo(Bar) {} // pass by reference c# (if it's a reference type ;))
void Foo(Bar&) {} // c++

void Foo(ref Bar) {} // c#
void Foo(Bar*) // c++

void Foo(out Bar) {} // c#
void Foo(Bar**) {} // c++ (the contents of *Bar needs to be filled up)

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

تحرير: مثال:

void mymethod(ref int a) {
  a++;
}

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

تحرير: مثال:

void mymethod2(out string a) {
  a="hello";
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top