ما الفرق بين الكلمات الرئيسية "المرجع" و "خارج"؟

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

سؤال

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

public void myFunction(ref MyClass someClass)

و

public void myFunction(out MyClass someClass)

التي يجب أن تستخدم ولماذا؟

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

المحلول

ref يروي المحول البرمجي أن الكائن يتم تهيئة قبل دخول الوظيفة، في حين out يروي المحول البرمجي أن الكائن سيتم تهيئة داخل الوظيفة.

وذلك في حين ref هو طريقتين، out خارج فقط.

نصائح أخرى

ال ref معدل يعني أن:

  1. تم تعيين القيمة بالفعل و
  2. يمكن أن تقرأ الطريقة وتعديلها.

ال out معدل يعني أن:

  1. لم يتم تعيين القيمة ولا يمكن قراءتها بواسطة الطريقة حتى تم تعيينه.
  2. طريقة يجب اضبطه قبل العودة.

دعنا نقول أن دوم تظهر في مقصورة بيتر حول المذكرة حول تقارير TPS.

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

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

سأحاول يدي في تفسير:

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

موافق على الجزء المربك، أنواع المراجع:

يتيح إنشاء نوع مرجع:

List<string> someobject = new List<string>()

عندما تصل simobject., ، يتم إنشاء جزأين:

  1. كتلة الذاكرة التي تحمل البيانات ل simobject..
  2. مرجع (مؤشر) بهذه الكتلة من البيانات.

الآن عند إرسالها simobject. في طريقة دون المرجع، نسخ المرجعي مؤشر وليس البيانات. لذلك لديك الآن هذا:

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

مرجعين يشيران إلى نفس الكائن. إذا قمت بتعديل خاصية على simobject. باستخدام المرجع 2، سوف يؤثر على نفس البيانات المدببة حسب المرجع 1.

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

إذا قمت بإخراج المرجع 2 أو توجيه البيانات الجديدة، فلن تؤثر على مرجع 1 ولا مرجع البيانات 1 نقطة.

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

الآن ماذا يحدث عند إرسال simobject. بواسطة المرجع إلى طريقة؟ ال المرجع الفعلي ل simobject. يتم إرسالها إلى الطريقة. لذلك لديك الآن مرجع واحد فقط إلى البيانات:

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

ولكن ماذا يعني هذا؟ إنه يعمل بالضبط نفس إرسال Someobject ليس بواسطة المرجع باستثناء شيءين رئيسيين:

1) عند إلغاء الإشارة داخل الأسلوب، فإنه سيغنى من الطريقة الخارجية.

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2) يمكنك الآن الإشارة إلى مرجع إلى موقع بيانات مختلف تماما والرجوع إلى الوظيفة، وسوف يشير الآن إلى موقع البيانات الجديد.

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true

المرجع في و خارج.

يجب عليك استخدامها out في التفضيل أينما تكفي لمتطلباتك.

خارج:

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

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

المرجع:

في C #، عند تمرير نوع قيمة مثل int، تعويم، مزدوج إلخ. كوسيطة لمعلمة الطريقة، يتم تمريرها حسب القيمة. لذلك، إذا قمت بتعديل قيمة المعلمة، فلا تؤثر على الوسيطة في مكالمة الأسلوب. ولكن إذا حددت المعلمة بكلمة رئيسية "REM"، فسوف تعكس في المتغير الفعلي.

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

يمتد الكلب، مثال القط. الطريقة الثانية مع ref يغير الكائن المشار إليها بواسطة المتصل. وبالتالي "القط" !!!

    public static void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog". 
        Bar(ref myObject);
        Console.WriteLine(myObject.Name); // Writes "Cat". 
    }

    public static void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

    public static void Bar(ref MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

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

مثال:

public void Foo()
{
    MyClass myObject = new MyClass();
    myObject.Name = "Dog";
    Bar(myObject);
    Console.WriteLine(myObject.Name); // Writes "Cat".
}

public void Bar(MyClass someObject)
{
    someObject.Name = "Cat";
}

طالما تمر في فصل لا يجب عليك استخدامه ref إذا كنت ترغب في تغيير الكائن داخل طريقتك.

ref و out تتصرف بالمثل إلا بعد الاختلافات.

  • ref يجب تهيئة المتغير قبل الاستخدام. out يمكن استخدام المتغير دون مهمة
  • out يجب التعامل مع المعلمة كقيمة غير محددة من خلال الوظيفة التي تستخدمه. لذلك، يمكننا استخدام تهيئة out المعلمة في رمز الاتصال، ولكن سيتم فقد القيمة عند تنفيذ الوظيفة.

بالنسبة لأولئك الذين يتعلمون حسب المثال (مثلي) إليك ما أنتوني كوليوسوف يقول.

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

https:gist.gist.github.com/2upmedia/6D98A57B68D849ee7091.

"خباز"

هذا لأن أول واحد يغير إشارة السلسلة الخاصة بك إلى الإشارة إلى "بيكر". تغيير المرجع ممكن لأنك مرت به عبر الكلمة الرئيسية REF (=> مرجع إلى مرجع إلى سلسلة). المكالمة الثانية تحصل على نسخة من المرجع إلى السلسلة.

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

string s = "Able";

ثم S هو مرجع إلى فئة سلسلة تحتوي على النص "القادر"! مهمة أخرى لنفس المتغير عبر

s = "Baker";

لا يغير السلسلة الأصلية ولكن فقط يخلق مثيل جديد ودعه نقطة إلى هذه الحالة!

يمكنك تجربته مع مثال الكود الصغير التالي:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

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

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

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


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

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

يوضح المثال التالي هذا:

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

المرجع:المعلمة المرجعية هي مرجع إلى موقع ذاكرة متغير. عند تمرير المعلمات عن طريق المرجع، على عكس معلمات القيمة، لا يتم إنشاء موقع تخزين جديد لهذه المعلمات. تمثل المعلمات المرجعية نفس موقع الذاكرة مثل المعلمات الفعلية التي يتم توفيرها للطريقة.

في C #، أنت تعلن المعلمات المرجعية باستخدام الكلمة الرئيسية REF. يوضح المثال التالي هذا:

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}

التعديل والخروج يعمل تماما مثل المرور بالمراجع والتمرير من قبل المؤشرات كما هو الحال في C ++.

ل REF، يجب أن تعلن الحجة والتهيئة.

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

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);

وقت التأليف:

(1) نخلق طريقة الاتصال Main()

(2) يقوم بإنشاء كائن قائمة (وهو كائن نوع مرجعي) ويقوم بتخزينه في المتغير myList.

public sealed class Program 
{
    public static Main() 
    {
        List<int> myList = new List<int>();

أثناء وقت التشغيل:

(3) تخصيص وقت التشغيل ذاكرة على المكدس في # 00، واسعة بما يكفي لتخزين عنوان (# 00 = myList, ، نظرا لأن الأسماء المتغيرة هي حقا أسماء مستعثية لمواقع الذاكرة)

(4) وقت التشغيل إنشاء كائن قائمة على كومة الكومة في موقع الذاكرة #FF (كل هذه العناوين مخصصة لها)

(5) تشغيل وقت التشغيل ثم تخزين عنوان البداية #FF للكائن في # 00 (أو بالكلمات، يخزن مرجع كائن القائمة في المؤشر myList)

العودة إلى تأليف الوقت:

(6) ثم اجتياز كائن القائمة كوسيطة myParamList إلى الطريقة المسمى modifyMyList وتعيين كائن قائمة جديدة إليه

List<int> myList = new List<int>();

List<int> newList = ModifyMyList(myList)

public List<int> ModifyMyList(List<int> myParamList){
     myParamList = new List<int>();
     return myParamList;
}

أثناء وقت التشغيل:

(7) بدء تشغيل وقت التشغيل روتين المكالمات للطريقة المسمى وكجزء منه، يتحقق من نوع المعلمات.

(8) عند العثور على نوع المرجع، فإنه يخصص ذاكرة على المكدس في # 04 لاستعراض متغير المعلمة myParamList.

(9) ثم يخزن القيمة #FF في ذلك أيضا.

(10) تشغيل وقت التشغيل إنشاء كائن قائمة على كومة الذاكرة في موقع الذاكرة # 004 ويستبدل #FF في # 04 مع هذه القيمة (أو تغيير كائن القائمة الأصلية وأشار إلى كائن القائمة الجديد في هذه الطريقة)

لا يتم تغيير العنوان الموجود في # 00 وتحتفظ بالإشارة إلى #FF (أو الأصل myList مؤشر غير مضطرب).


ال رجع الكلمة الرئيسية هي توجيه مترجم لتخطي جيل رمز وقت التشغيل (8) و (9) مما يعني أنه لن يكون هناك تخصيص كومة لمعلمات الأسلوب. سيستخدم مؤشر رقم 00 الأصلي للعمل على الكائن في #FF. إذا لم يتم إهتمام المؤشر الأصلي، فسوف يتوقف وقت التشغيل يشتكي من أنه لا يمكن متابعةه لأن المتغير لم يتم تهيئته

ال خارج الكلمة الرئيسية هي توجيه مترجم يمثل إلى حد كبير هو نفس المرجع مع تعديل طفيف في (9) و (10). يتوقع المحول البرمجي أن تكون الحجة غير مهمة وسوف تستمر مع (8) و (4) و (5) إنشاء كائن على كومة كومة وتخزين عنوانها البداية في متغير الوسيطة. لن يتم إلقاء أي خطأ غير مهتم وسيتم فقد أي مرجع سابق تخزينه.

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

int x;    Foo(out x); // OK 
int y;    Foo(ref y); // Error

المعلمات المرجعية هي للبيانات التي قد يتم تعديلها، والمعلمات الخارجية مخصصة للبيانات مخرج إضافي لهذه الوظيفة (مثل int.tryparse) التي تستخدم بالفعل قيمة الإرجاع لشيء ما.

أدناه لقد أظهرت مثالا باستخدام كليهما رجع و خارج. وبعد الآن، سيتم مسح جميعا حول المرجع والخروج.

في المثال المذكور أدناه عندما أعلق // myrefobj = myclass new new {name = "rev outday يسمى!"}؛خط، سوف تحصل على خطأ يقول "استخدام المتغير المحلي غير المعين" myrefobj ", ، ولكن لا يوجد مثل هذا الخطأ في خارج.

حيث لاستخدام المرجع: عندما ندعو إجراء مع المعلمة في المعلمة، سيتم استخدام المعلمة نفسها لتخزين إخراج هذا PROC.

حيث تستخدم خارج: عندما ندعو إجراء لا يوجد في المعلمة، سيتم استخدام نفس التعرف على نفس المعلمة لإرجاع القيمة من هذا proc. لاحظ أيضا الإخراج

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 
 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

يمكنك التحقق من هذا الرمز، وسوف يصفك DifferNce الكامل عند استخدام "المرجع" تعني أنه تهيئة بالفعل تلك الدولية / السلسلة

ولكن عند استخدام "Out"، فإنه يعمل في كلا الشرطين Weather يو تهيئة تلك الدولية / السلسلة أو لا يجب عليك تهيئة تلك الدولية / السلسلة في هذه الوظيفة

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

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

public class Example
{
 public static void Main() 
 {
 int val1 = 0; //must be initialized 
 int val2; //optional

 Example1(ref val1);
 Console.WriteLine(val1); 

 Example2(out val2);
 Console.WriteLine(val2); 
 }

 static void Example1(ref int value) 
 {
 value = 1;
 }
 static void Example2(out int value) 
 {
 value = 2; 
 }
}

/* Output     1     2     

المرجع والخروج في طريقة الزائدة

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

من وجهة نظر الطريقة التي تتلقى معلمة، الفرق بين ref و out هو أن C # يتطلب أن الكتابة إلى كل out المعلمة قبل العودة، ويجب ألا تفعل أي شيء مع مثل هذه المعلمة، بخلاف تمريرها ك out المعلمة أو الكتابة إليها، حتى يتم تمريرها ك out المعلمة إلى طريقة أخرى أو مكتوبة مباشرة. لاحظ أن بعض اللغات الأخرى لا تفرض مثل هذه المتطلبات؛ طريقة افتراضية أو واجهة تم الإعلان عنها في C # مع out قد يتم تجاوز المعلمة بلغة أخرى لا تفرض أي قيود خاصة على هذه المعلمات.

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

struct MyStruct
{
   ...
   myStruct(IDictionary<int, MyStruct> d)
   {
     d.TryGetValue(23, out this);
   }
}

إذا myDictionary يحدد an. IDictionary<TKey,TValue> التنفيذ مكتوب بلغة أخرى غير C #، على الرغم من MyStruct s = new MyStruct(myDictionary); يبدو وكأنه مهمة، يمكن أن يغادر s غير محدد.

لاحظ أن المنشئين المكتوبة في VB.NET، على عكس أولئك الموجودين في C #، لا يقدمون افتراضات حول ما إذا كانت الأساليب ستعدل أي out المعلمات، واضحة جميع الحقول دون قيد أو شرط. لن يحدث السلوك الغريب مع الأعلى أعلاه به مع التعليمات البرمجية المكتوبة بالكامل في VB أو كليا في C #، ولكن يمكن أن يحدث عندما يستدعي التعليمات البرمجية المكتوبة في C # طريقة مكتوبة في VB.NET.

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

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

  • أنت لا تحتاج ref أو out إذا كان كل ما ستفعله هو تعديل الأشياء في داخل ال MyClass المثال الذي تم تمريره في الحجة someClass.

    • طريقة الاتصال سوف ترى تغييرات مثل someClass.Message = "Hello World" سواء كنت تستخدم ref, out أو لا شيء
    • كتابة someClass = new MyClass() في داخل myFunction(someClass) مقايضة الكائن الذي شوهه someClass في نطاق myFunction الطريقة فقط. لا تزال طريقة الاتصال تعرف عن الأصل MyClass مثيل تم إنشاؤه ومرت إليه إلى طريقة
  • أنت يحتاج ref أو out إذا كنت تخطط في تبادل someClass خارج كائن جديد كامل وتريد طريقة الاتصال لرؤية التغيير الخاص بك

    • كتابة someClass = new MyClass() في داخل myFunction(out someClass) يغير الكائن الذي ينص عليه الطريقة التي تسمى myFunction

مبرمجون آخرون

ويريدون أن يعرفوا ما ستفعله مع بياناتهم. تخيل أنك تكتب مكتبة سيتم استخدامها بملايين المطورين. تريد منهم أن يعرفوا ما ستفعله بمتغيراتهم عند استدعاء أساليبك

  • استخدام ref يقدم بيان "تمرير متغير معين إلى بعض القيمة عند استدعاء طريقتي. كن على علم بأنني قد أغيره لشيء آخر بالكامل أثناء طريقتي. لا تتوقع أن يشير المتغير إلى الكائن القديم انتهيت"

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

بالمناسبة، في C # 7.2 هناك in معدل أيضا

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


فعلت مايكروسوفت هذا مع .TryParse الأساليب على الأنواع الرقمية:

int i = 98234957;
bool success = int.TryParse("123", out i);

عن طريق رفع المعلمة كما out إنهم يعلنون بنشاط هنا "نحن بالتااكيد الذهاب لتغيير القيمة المصممة بشدة 98234957 للخارج لشيء آخر "

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

public void PoorlyNamedMethod(out SomeClass x)

يمكنك أن ترى انها out, ، وبالتالي يمكنك أن تعرف أنه إذا كنت تقضي ساعات في الطحن أرقام، فقم بإنشاء SomeClass المثالي:

SomeClass x = SpendHoursMakingMeAPerfectSomeClass();
//now give it to the library
PoorlyNamedMethod(out x);

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

مانع جيدا أن المعلمة المرجعية التي يتم تمريرها داخل الوظيفة تعمل مباشرة على.

علي سبيل المثال،

    public class MyClass
    {
        public string Name { get; set; }
    }

    public void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog".
    }

    public void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

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

قد لا أكون جيدا في هذا الأمر، ولكن السلاسل بالتأكيد (على الرغم من أنها لأنها أنواع مرجعية تقنيا والعيش على كومة) يتم تمريرها حسب القيمة، وليس الرجوع؟

        string a = "Hello";

        string b = "goodbye";

        b = a; //attempt to make b point to a, won't work.

        a = "testing";

        Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

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

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

يمكن أن أكون مخطئا تماما هنا رغم ذلك، أنا جديد.

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