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

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

  •  02-07-2019
  •  | 
  •  

سؤال

ليس لدي هذه المشكلة حاليا, لكنك لا تعرف أبدًا، والتجارب الفكرية ممتعة دائمًا.

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

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

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

كيف ستحاول معالجة هذه المشكلة؟

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

المحلول

من الواضح جدًا أنك ستكتب التعليمات البرمجية في VB.NET، والتي تحتوي بالفعل على خطأ في الصفحة، إذهب للتالي, وتصديره في ملف DLL إلى C#.أي شيء آخر هو مجرد نراتين للعقاب.

نصائح أخرى

public delegate void VoidDelegate();

public static class Utils
{
  public static void Try(VoidDelegate v) {
    try {
      v();
    }
    catch {}
  }
}

Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );

إعادة البناء إلى طرق فردية معروفة جيدًا:

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

كل واحد منهم محمي بشكل مناسب.

أود أن أقول لا تفعل شيئا.

نعم هذا صحيح، لا تفعل شيئا.

لقد حددت لي بوضوح شيئين:

  1. أنت تعرف أن الهندسة المعمارية فاشلة.
  2. هناك طن من هذا هراء.

انا اقول:

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

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

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

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

اخفاق سريع

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

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

لذا، إذا كان هذا هو C++، فيمكنك القيام بشيء مثل هذا:

#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);

لسوء الحظ، لا يبدو أن العديد من اللغات تتضمن معالجًا مسبقًا مثل C/C++.

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

ومع ذلك، أعتقد أن هذه أفكار فظيعة ولا ينبغي القيام بها أبدًا، ولكن تم طرح السؤال.:)

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

On Error Resume Next هي فكرة سيئة حقًا في عالم C#.ولن إضافة ما يعادلها ل On Error Resume Next مساعدتك في الواقع.كل ما سيفعله هو تركك في حالة سيئة قد تسبب المزيد من الأخطاء الدقيقة وفقدان البيانات وربما تلف البيانات.

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

كما ذكر أحد الأشخاص، VB يسمح بذلك.ماذا عن القيام بنفس الطريقة في C#؟أدخل عاكسًا موثوقًا به:

هذا:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

يترجم إلى هذا:

public static void Main()
{
    // This item is obfuscated and can not be translated.
    int VB$ResumeTarget;
    try
    {
        int VB$CurrentStatement;
    Label_0001:
        ProjectData.ClearProjectError();
        int VB$ActiveHandler = -2;
    Label_0009:
        VB$CurrentStatement = 2;
        int i = 0;
    Label_000E:
        VB$CurrentStatement = 3;
        int y = (int) Math.Round((double) (5.0 / ((double) i)));
        goto Label_008F;
    Label_0029:
        VB$ResumeTarget = 0;
        switch ((VB$ResumeTarget + 1))
        {
            case 1:
                goto Label_0001;

            case 2:
                goto Label_0009;

            case 3:
                goto Label_000E;

            case 4:
                goto Label_008F;

            default:
                goto Label_0084;
        }
    Label_0049:
        VB$ResumeTarget = VB$CurrentStatement;
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
        {
            case 0:
                goto Label_0084;

            case 1:
                goto Label_0029;
        }
    }
    catch (object obj1) when (?)
    {
        ProjectData.SetProjectError((Exception) obj1);
        goto Label_0049;
    }
Label_0084:
    throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
    if (VB$ResumeTarget != 0)
    {
        ProjectData.ClearProjectError();
    }
}

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

قد يساعدك هذا في تحديد القطع التي بها أكبر قدر من المشاكل.

@ JB King شكرًا لتذكيرني.تحتوي كتلة تطبيق التسجيل على حدث أجهزة يمكن استخدامه لتتبع الأحداث، ويمكنك العثور على مزيد من المعلومات في مستندات مكتبة MS Enterprise.

Using (New InstEvent)
<series of statements> 
End Using

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

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

أنت استطاع استخدم goto، لكنه لا يزال فوضويًا.

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

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

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

هذا الأسلوب غير ممكن اليوم مع .NET 3.5 - إذا لم يكن هناك سبب آخر غير عدم وجود عبارة "محاولة" في System.Linq.Expressions.ومع ذلك، قد يكون قابلاً للتطبيق في إصدار مستقبلي من C# بمجرد اكتمال دمج أشجار التعبير DLR وLINQ.

لماذا لا تستخدم الانعكاس في C#؟يمكنك إنشاء فئة تعكس الكود واستخدام السطر # كتلميح لما يجب وضعه في كل كتلة محاولة/التقاط فردية.هذا له بعض المزايا:

  1. إنه أقل قبحًا قليلاً لأنه لا يتطلب حقًا تشويه كود المصدر الخاص بك ويمكنك استخدامه فقط أثناء أوضاع تصحيح الأخطاء.
  2. ستتعلم شيئًا مثيرًا للاهتمام حول لغة C# أثناء تنفيذها.

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

سؤال ممتع؛سيء جدا.

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

من خلال العبث بهذا، حاولت تصنيف كل سطر والقفز مرة أخرى من نقطة صيد واحدة، دون أن يحالفني الحظ.لكن، كشف كريستوفر عن الطريقة الصحيحة للقيام بذلك.هناك بعض مناقشة إضافية مثيرة للاهتمام حول هذا الموضوع في Dot Net Thoughts وفي مدونة مايك ستال .NET.

يحرر:بالطبع.ال try-catch / switch-goto لن يتم تجميع الحل المدرج فعليًا منذ try التسميات خارج النطاق في catch.هل يعرف أحد ما هو الشيء المفقود لإنشاء شيء مثل هذا التجميع؟

يمكنك أتمتة هذا من خلال خطوة المعالجة المسبقة للمترجم أو ربما الاختراق أداة Inline IL الخاصة بـ Mike Stall لحقن بعض الخطأ والجهل.

(إجابة أوريون أدريان حول فحص الاستثناء ومحاولة تعيين التعليمات التالية أمر مثير للاهتمام أيضًا.)

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

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

لسوء الحظ، ربما لم يحالفك الحظ.On Error Resume Next هو خيار قديم لا يُنصح به بشدة بشكل عام، وليس له ما يعادل معرفتي في C#.

أوصي بترك الكود في VB (يبدو أن هذا هو المصدر، نظرًا لطلبك المحدد لـ OnError ResumeNext) والتفاعل مع أو من ملف C# dll أو exe الذي ينفذ أي كود جديد تحتاجه.بعد ذلك، قم بإعادة التصميم مسبقًا لجعل الكود آمنًا، وقم بتحويل هذا الكود الآمن إلى C# أثناء قيامك بذلك.

يمكنك النظر في دمج مكون معالجة الاستثناءات في مكتبة المؤسسة للحصول على فكرة واحدة حول كيفية التعامل مع الاستثناءات غير المعالجة.

إذا كان هذا مخصصًا لتطبيقات ASP.Net، فهناك وظيفة في Global.asax تسمى "Application_Error" والتي يتم استدعاؤها في معظم الحالات ويكون الفشل الذريع هو الحالة الأخرى عادةً.

تجاهل جميع الأسباب التي تجعلك ترغب في تجنب القيام بذلك .......

إذا كان الأمر مجرد حاجة إلى الاحتفاظ بعدد # من الأسطر، فيمكنك تجربة شيء مثل:

int totalMethodCount = xxx;
for(int counter = 0; counter < totalMethodCount; counter++) {
    try {
        if (counter == 0) WidgetMaker.SetAlignment(57);
        if (counter == 1) contactForm["Title"] = txtTitle.Text;
        if (counter == 2) Casserole.Season(true, false);
        if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
    } catch (Exception ex) {
        // log here
    }
}

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

قم بقص كل سطر، واحدًا تلو الآخر، "أحيط بـ" حاول/التقط.وهذا يتجنب النسخ واللصق الذي ذكرته

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