سؤال

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

VoidFunction t = delegate { int i = 0; };

int i = 1;

انها تقول:

لا يمكن إعلان متغير محلي يسمى "I" في هذا النطاق لأنه سيعطي معنى مختلفًا لـ "I" ، والذي يستخدم بالفعل في نطاق "طفل" للدلالة على شيء آخر

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

لذلك أنا أتساءل ماذا يفعل الآخرون للتغلب على هذه القضية؟

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

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

المحلول

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

تتمثل الحلول في استخدام أسماء مختلفة للمتغير ، أو إنشاء طريقة عادية.

نصائح أخرى

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

function thing() {
    var o1 = {n:1}
    var o2 = {dummy:"Hello"}
    return function() { return o1.n++; }
}

var fn = thing();
alert(fn());
alert(fn());

سيتم عرض قطعة صغيرة من JavaScript 1 ثم 2. يمكن للدالة المجهولة الوصول إلى متغير O1 لأنه موجود في سلسلة النطاق الخاصة به. ومع ذلك ، فإن الوظيفة المجهولة لديها نطاق مستقل تمامًا يمكن أن يخلق فيه متغيرًا آخر O1 وبالتالي يخفي أي سلسلة أخرى أخرى أسفل سلسلة النطاق. لاحظ أيضًا أن جميع المتغيرات في السلسلة بأكملها تبقى ، وبالتالي فإن O2 ستستمر في وجود مرجع كائن طالما يحتفظ FN Varialbe مرجع الوظيفة.

قارن الآن مع C# الوظائف المجهولة:-

class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }

Func<int> thing() {
   var o1 = new C1() {n=1};
   var o2 = new C2() {dummy="Hello"};
   return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());

في هذه الحالة ، فإن الوظيفة المجهولة لا تنشئ نطاقًا مستقلًا تمامًا أكثر من إعلان متغير في أي كتلة أخرى من الكود ( foreach, if, ، إلخ.)

وبالتالي تنطبق نفس القواعد ، لا يمكن للكود خارج الكتلة الوصول إلى متغيرات المعلن داخل الكتلة ولكن لا يمكنك إعادة استخدام معرف أيضًا.

يتم إنشاء إغلاق عندما يتم تمرير الوظيفة المجهولة خارج الوظيفة التي تم إنشاؤها فيها. إن الاختلاف من مثال JavaScript هو أن تلك المتغيرات المستخدمة فعليًا في الواقع هي التي ستبقى ، وبالتالي في هذه الحالة ، الكائن الذي تحتفظ به O2 Will تكون متاحة لشركة GC بمجرد اكتمال الأمر ،

ستحصل أيضًا على CS0136 من كود مثل هذا:

  int i = 0;
  if (i == 0) {
    int i = 1;
  }

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

الحل التافه وغير مؤلم ، فقط توصل إلى اسم متغير مختلف.

ذلك لأن المندوب يمكنه الرجوع إلى المتغيرات خارج المندوب:

int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };

إذا كنت أتذكر بشكل صحيح ، فإن المترجم ينشئ عضوًا في الفصل من المتغيرات الخارجية المشار إليها في الطريقة المجهولة ، من أجل جعل هذا العمل.

هنا حل بديل:

class Program
    {
        void Main()
        {
            VoidFunction t = RealFunction;
            int i = 1;
        }
        delegate void VoidFunction();
        void RealFunction() { int i = 0; }
    } 

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

using System;

class Program
{
    static void Main()
    {
        // Action t = delegate
        {
            int i = 0;
        };

        int i = 1;
    }
}

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

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