c# - الفرق بين المعلمات ref و out في.NET




(16)

ما هو الفرق بين المعلمات ref و out في .NET؟ ما هي الحالات التي يمكن للمرء فيها أن يكون أكثر فائدة من الآخر؟ ماذا يمكن أن يكون مقتطف شفرة حيث يمكن استخدام أحدهما والآخر لا يمكن؟


Answers

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


  • يجب تهيئة متغير ref قبل تمريره.
  • يجب تعيين متغير out في تطبيق الدالة الخاص بك
  • يمكن اعتبار المعلمات out كمتغيرات عودة إضافية (وليس مدخلات)
  • يمكن اعتبار المعلمات ref كمتغيرات الإدخال والإخراج.

هم مختلفين بمهارة.

لا يحتاج الأمر إلى تهيئة المعلمة الخارجية قبل أن يتم تمريرها إلى الطريقة. لذلك ، أي طريقة مع معلمة out

  • لا يمكن قراءة المعلمة قبل تعيين قيمة لها
  • يجب تعيين قيمة لها قبل العودة

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

يجب تهيئة المعلمة ref من قبل المستدعي قبل تمريرها إلى الطريقة. لذلك ، أي طريقة مع معلمة ref

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

يستخدم هذا الأسلوب الذي يجب (على سبيل المثال) فحص قيمته والتحقق من صحته أو تطبيعه.


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

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

لمزيد من التفاصيل ، انظر إلى http://www.blackwasp.co.uk/CSharpMethodParameters.aspx



مثال لـ OUT: يتم تهيئة القيمة المتغيرة بعد الانتقال إلى الطريقة. في وقت لاحق يتم إرجاع نفس القيمة إلى الطريقة الرئيسية.

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            // u can try giving int i=100 but is useless as that value is not passed into
            // the method. Only variable goes into the method and gets changed its
            // value and comes out. 
            int i; 

            a.abc(out i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(out int i)
        {

            i = 10;

        }

    }
}

انتاج:

10

===============================================

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

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            int i = 0;

            a.abc(ref i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(ref int i)
        {
            System.Console.WriteLine(i);
            i = 10;

        }

    }
}

انتاج:

    0
    10

=================================

نأمل في واضحة الآن.



تحدد المعلمة أن المعلمة هي معلمات خرج ، أي أنه لا قيمة لها حتى يتم تحديدها بوضوح بواسطة الطريقة.

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


مرجع و خارج المعلمات:

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

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

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

int sampleData = 0; 
sampleMethod(ref sampleData);

مثال على مرجع Ref

public static void Main() 
{ 
 int i = 3; // Variable need to be initialized 
 sampleMethod(ref i );  
}

public static void sampleMethod(ref int sampleData) 
{ 
 sampleData++; 
} 

Out Out Parameter: ليس من الضروري أن يتم التهيئة قبل المرور إلى Method. يمكن استخدام المعلمة الخارجية لإرجاع القيم في نفس متغير تمرير كمعلمة من الأسلوب. ستنعكس أي تغييرات يتم إجراؤها على المعلمة في المتغير.

 int sampleData; 
 sampleMethod(out sampleData);

خروج خارج المعلمة

public static void Main() 
{ 
 int i, j; // Variable need not be initialized 
 sampleMethod(out i, out j); 
} 
public static int sampleMethod(out int sampleData1, out int sampleData2) 
{ 
 sampleData1 = 10; 
 sampleData2 = 20; 
 return 0; 
} 

ref out حد سواء تسمح للطريقة المسماة لتعديل المعلمة. الفرق بينهما هو ما يحدث قبل إجراء المكالمة.

  • ref تعني أن المعلمة لها قيمة عليها قبل الانتقال إلى الوظيفة. يمكن للوظيفة المسماة قراءة و / أو تغيير القيمة في أي وقت. يدخل المعلمة ، ثم يخرج

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

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

// This is not C#
public (bool, string) GetWebThing(string name, ref Buffer paramBuffer);

// This is C#
public bool GetWebThing(string name, ref Buffer paramBuffer, out string actualUrl);

فيما يلي قائمة أكثر تفصيلاً لتأثيرات كل بديل:

قبل استدعاء الطريقة:

ref : يجب على المتصل تعيين قيمة المعلمة قبل تمريرها إلى الأسلوب الذي تم استدعاءه.

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

خلال المكالمة:

ref : يمكن للطريقة المسماة قراءة الحجة في أي وقت.

out : يجب استدعاء الأسلوب استدعاء المعلمة قبل قراءتها.

المكالمات المنبثقة:

ref : يتم تنظيم القيمة الحالية إلى المكالمة عن بُعد. تكلفة اضافية الاداء.

out : لا يتم تمرير أي شيء إلى المكالمة عن بعد. بسرعة.

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


خارج و ref هي نفسها تماما مع الاستثناء الذي لا يلزم تهيئة المتغيرات خارج قبل إرسالها إلى الهاوية. أنا لست ذكية ، أنا cribbed ذلك من مكتبة MSDN :).

ولكن لكي تكون أكثر وضوحًا بشأن استخدامها ، فإن معنى المعدل هو أنه في حالة تغيير مرجع هذا المتغير في شفرتك ، فإن الخروج والرجوع سيؤدي إلى تغيير متغير الاتصال الخاص بك أيضًا. في الكود أدناه ، سيكون المتغير الرئيسي مرجعًا لـ newGuy بمجرد عودته من المكالمة إلى doStuff. إذا لم يكن المرجع (أو الخروج) لن يتم تغيير المرجع.

private void newEmployee()
{
    Person ceo = Person.FindCEO();
    doStuff(ref ceo);
}

private void doStuff(ref Person employee)
{
    Person newGuy = new Person();
    employee = newGuy;
}

المعلمة out هي معلمة ref مع سمة Out() خاصة مضافة. إذا تم الإعلان عن معلمة إلى طريقة C # ، فسيطلب المحول البرمجي كتابة المعلمة قبل قراءتها وقبل أن تعود الطريقة. إذا كان C # يستدعي أسلوباً تتضمن Out() سمة Out() ، سيقوم المترجم ، لأغراض تحديد ما إذا كان سيتم الإبلاغ عن أخطاء "متغير غير معرف" ، بالتظاهر بأن المتغير قد تمت كتابته مباشرة قبل استدعاء الطريقة. لاحظ أنه نظرًا لأن لغات .net الأخرى لا تقوم بإرفاق نفس المعنى للسمة Out() ، فمن الممكن أن يؤدي استدعاء إجراء مع معلمة out إلى ترك المتغير المعني غير متأثر. إذا تم استخدام متغير كمعامل خارجي قبل تعيينه بالتأكيد ، سيعمل مترجم C # على إنشاء تعليمات برمجية للتأكد من أنه يتم مسحها في مرحلة ما قبل استخدامها ، ولكن إذا ترك هذا المتغير النطاق أو أعاد إدخاله ، فليس هناك ضمان أنه سيتم مسحها مرة أخرى.


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


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


خارج:

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

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

المرجع:

في C # ، عندما تقوم بتمرير نوع قيمة مثل int ، أو float ، أو double إلخ ، كوسيطة لمعلمة الأسلوب ، يتم تمريرها حسب القيمة. لذلك ، إذا قمت بتعديل قيمة المعلمة ، لا يؤثر على الوسيطة في استدعاء الأسلوب. ولكن إذا وضعت علامة على المعلمة بكلمة "ref" ، فستظهر في المتغير الفعلي.

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

This reminds me of the "Is a" versus "has a" tradeoff. Sometimes it is easier and makesmore sense to inherit directly from a super class. Other times it makes more sense to create a standalone class and include the class you would have inherited from as a member variable. You can still access the functionality of the class but are not bound to the interface or any other constraints that might come from inheriting from the class.

Which do you do? As with a lot of things...it depends on the context. The guide I would use is that in order to inherit from another class there truly should be an "is a" relationship. So if you a writing a class called BMW, it could inherit from Car because a BMW truly is a car. A Horse class can inherit from the Mammal class because a horse actually is a mammal in real life and any Mammal functionality should be relevant to Horse. But can you say that a team is a list? From what I can tell, it does not seem like a Team really "is a" List. So in this case, I would have a List as a member variable.





c# .net