سؤال

كنت أعمل مع روتين صغير يستخدم لإنشاء اتصال بقاعدة البيانات:

قبل

public DbConnection GetConnection(String connectionName)
{
   ConnectionStringSettings cs= ConfigurationManager.ConnectionStrings[connectionName];
   DbProviderFactory factory = DbProviderFactories.GetFactory(cs.ProviderName);
   DbConnection conn = factory.CreateConnection();
   conn.ConnectionString = cs.ConnectionString;
   conn.Open();

   return conn;
}

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

على سبيل المثال:

ConfigurationManager.ConnectionStrings...

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


الجزء التالي هو الفهرسة الفعلية لل سلاسل الاتصال لايجاد اسم الاتصال:

...ConnectionStrings[connectionName];

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

ConnectionStringSettings cs= 
      ConfigurationManager.ConnectionStrings[connectionName];
if (cs == null)
   throw new ArgumentException("Could not find connection string \""+connectionName+"\"");

أكرر نفس التمرين مع:

DbProviderFactory factory = 
      DbProviderFactories.GetFactory(cs.ProviderName);

ال GetFactory لا تحتوي الطريقة على وثائق حول ما يحدث إذا تم إنشاء مصنع للملف المحدد ProviderName لا يمكن العثور عليها.لم يتم توثيق العودة null, ، ولكن لا يزال بإمكاني أن أكون دفاعيًا، و يفحص للخالية:

DbProviderFactory factory = 
      DbProviderFactories.GetFactory(cs.ProviderName);
if (factory == null) 
   throw new Exception("Could not obtain factory for provider \""+cs.ProviderName+"\"");

التالي هو إنشاء كائن DbConnection:

DbConnection conn = factory.CreateConnection()

مرة أخرى توثيق لا يذكر ما يحدث إذا لم يتمكن من إنشاء اتصال، ولكن مرة أخرى يمكنني التحقق من وجود كائن إرجاع فارغ:

DbConnection conn = factory.CreateConnection()
if (conn == null) 
   throw new Exception.Create("Connection factory did not return a connection object");

التالي هو تعيين خاصية كائن الاتصال:

conn.ConnectionString = cs.ConnectionString;

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


وأخيرًا، فتح اتصال قاعدة البيانات:

conn.Open();

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


بعد

public DbConnection GetConnection(String connectionName)
{
   //Get the connection string info from web.config
   ConnectionStringSettings cs= ConfigurationManager.ConnectionStrings[connectionName];

   //documented to return null if it couldn't be found
    if (cs == null)
       throw new ArgumentException("Could not find connection string \""+connectionName+"\"");

   //Get the factory for the given provider (e.g. "System.Data.SqlClient")
   DbProviderFactory factory = DbProviderFactories.GetFactory(cs.ProviderName);

   //Undefined behaviour if GetFactory couldn't find a provider.
   //Defensive test for null factory anyway
   if (factory == null)
      throw new Exception("Could not obtain factory for provider \""+cs.ProviderName+"\"");

   //Have the factory give us the right connection object
   DbConnection conn = factory.CreateConnection();

   //Undefined behaviour if CreateConnection failed
   //Defensive test for null connection anyway
   if (conn == null)
      throw new Exception("Could not obtain connection from factory");

   //Knowing the connection string, open the connection
   conn.ConnectionString = cs.ConnectionString;
   conn.Open()

   return conn;
}

ملخص

لذلك أصبحت وظيفتي المكونة من أربعة أسطر 12 سطرًا، وتتطلب 5 دقائق من البحث عن الوثائق.في النهاية، اكتشفت حالة واحدة حيث يُسمح للطريقة بإرجاع قيمة فارغة.ولكن من الناحية العملية، كل ما فعلته هو تحويل استثناء انتهاك الوصول (إذا حاولت استدعاء الأساليب على مرجع فارغ) إلى ملف InvalidArgumentException.

لقد التقطت أيضًا حالتين محتملتين حيث يمكن أن يكون هناك باطل كائنات العودة؛ولكن مرة أخرى قمت بالتداول باستثناء واحد فقط لآخر.

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

ولكن هل يستحق كل هذا العناء؟هل هذه مبالغة؟فهل انحرفت هذه البرمجة الدفاعية؟

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

المحلول

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

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

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

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

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

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

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

نصائح أخرى

حسنًا، يعتمد الأمر على من هو جمهورك.

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

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

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

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

القبعات لك إيان.أستطيع أن أفهم معضلتك.لقد مررت بنفس الشيء بنفسي.ولكن ما فعلته ربما ساعد بعض المطورين على قضاء عدة ساعات في ضرب لوحة المفاتيح.

تذكر، عندما تستخدم واجهة برمجة تطبيقات .net Framework، ماذا تتوقع منها؟ما الذي يبدو طبيعيا؟افعل نفس الشيء مع الكود الخاص بك.

أعلم أن الأمر يستغرق وقتًا.ولكن بعد ذلك تأتي الجودة بتكلفة.

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

يتميز مثالك "قبل" بكونه واضحًا وموجزًا.

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

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

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

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

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

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

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

لن أقوم بالتحقق من المرجع الفارغ على GetFactory و CreateConnection المكالمات سواء.كيف تكتب حالة اختبار لممارسة هذا الرمز؟لا يمكنك ذلك، لأنك لا تعرف كيفية جعل هذه الأساليب تعود فارغة - حتى أنك لا تعرف أنها كذلك ممكن لجعل هذه الأساليب تعود فارغة.لقد قمت باستبدال مشكلة واحدة - يمكن لبرنامجك أن يرمي ملف NullReferenceException في ظل ظروف لا تفهمها - مع شرط آخر أكثر أهمية:وفي ظل نفس الظروف الغامضة، سيقوم برنامجك بتشغيل تعليمات برمجية لم تختبرها.

قاعدتي الأساسية هي:

DOCTYPE html> <html lang=en> <meta charset=utf-8> <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width"> <title>Error 400 (Bad Request)!!1</title> <style> *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px} </style> <a href=//www.google.com/><span id=logo aria-label=Google></span></a> <p><b>400.</b> <ins>That’s an error.</ins> <p>Your client has issued a malformed or illegal request. <ins>That’s all we know.</in

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

الاستثناء الوحيد هو إذا كان "عقد" GetConnection لا يسترد سلسلة الاتصال بالضرورة في ملف التكوين.

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

الحل الآخر هو تحديد أن GetConnection لا يمكنه الرمي (لكن يمكنه إرجاع قيمة خالية)، ثم تقوم بإضافة "ExceptionHandler" إلى الفصل الدراسي الخاص بك.

وثائق الطريقة الخاصة بك مفقودة.؛-)

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

  • إذا كان من المفترض أن تكشف طريقتك عن معلومات تفصيلية عن السبب والأشياء التي فشلت، فافعل ذلك كما فعلت وتحقق من كل شيء والتقطه وأعد المعلومات المناسبة.

  • ولكن، إذا كنت مهتمًا فقط بـ DBConnection مفتوح أو فقط باطل (أو بعض الاستثناءات التي يحددها المستخدم) في حالة الفشل، ثم قم فقط بلف كل شيء في محاولة/التقاط والعودة باطل (أو بعض الاستثناءات) على الخطأ، وعلى كائن آخر.

لذلك أود أن أقول إن ذلك يعتمد على سلوك الطريقة والإخراج المتوقع.

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

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

  1. مربك.
  2. اختراق أمني محتمل.
  3. محرجة لصورة شركتك (تخيل عميلاً يقرأ رسالة خطأ تحتوي على قواعد نحوية فظة).

كنت سأقوم بترميزها تمامًا مثل محاولتك الأولى.

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

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

النسخة المعدلة لا تضيف قيمة كبيرة، طالما أن التطبيق يحتوي على AppDomain.UnexpectedException المعالج الذي يتخلص من exception.InnerException سلسلة وكافة آثار المكدس إلى ملف سجل من نوع ما (أو حتى أفضل، يلتقط تفريغًا مصغرًا) ثم اتصل Environment.FailFast.

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

لاحظ أنه من الأفضل التعامل معها AppDomain.UnexpectedException و اتصل Environment.FailFast بدلا من الحصول على المستوى الأعلى try/catch (Exception x) لأنه مع هذا الأخير، من المحتمل أن يتم حجب السبب الأصلي للمشكلة من خلال المزيد من الاستثناءات.

هذا لأنه إذا حصلت على استثناء، أي مفتوح finally سيتم تنفيذ الكتل، ومن المحتمل أن تؤدي إلى المزيد من الاستثناءات، والتي ستخفي الاستثناء الأصلي (أو الأسوأ من ذلك، أنها ستحذف الملفات في محاولة لاستعادة بعض الحالات، وربما الملفات الخاطئة، وربما حتى الملفات المهمة).يجب ألا تكتشف أبدًا استثناءً يشير إلى حالة برنامج غير صالحة لا تعرف كيفية التعامل معها - حتى في المستوى الأعلى main وظيفة try/catch حاجز.معالجة AppDomain.UnexpectedException والاتصال Environment.FailFast هي غلاية أسماك مختلفة (ومرغوبة أكثر)، لأنها تتوقف finally كتل من التشغيل، وإذا كنت تحاول إيقاف برنامجك وتسجيل بعض المعلومات المفيدة دون إحداث المزيد من الضرر، فأنت بالتأكيد لا تريد تشغيل برنامجك finally كتل.

لا تنس التحقق من OutOfMemoryExceptions...أنت تعرفها قد يحدث.

تبدو التغييرات التي أجراها إيان معقولة بالنسبة لي.

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

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

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

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

في نظري، عينتك "ما بعد" ليست دفاعية حقًا.لأن الدفاع سيكون فحص الأجزاء التي تحت سيطرتك، والتي ستكون الحجة connectionName (تحقق من وجود قيمة فارغة أو فارغة، ثم قم بطرح ArgumentNullException).

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

شيء من هذا القبيل (تم تحريره في محرر SO، لذلك لا يتم التحقق من بناء الجملة/المترجم.قد لا يتم تجميع ؛-))

private string GetConnectionString(String connectionName)
{

   //Get the connection string info from web.config
   ConnectionStringSettings cs= ConfigurationManager.ConnectionStrings[connectionName];

   //documented to return null if it couldn't be found
   if (cs == null)
       throw new ArgumentException("Could not find connection string \""+connectionName+"\"");
   return cs;
}

private DbProviderFactory GetFactory(String ProviderName)
{
   //Get the factory for the given provider (e.g. "System.Data.SqlClient")
   DbProviderFactory factory = DbProviderFactories.GetFactory(ProviderName);

   //Undefined behaviour if GetFactory couldn't find a provider.
   //Defensive test for null factory anyway
   if (factory == null)
      throw new Exception("Could not obtain factory for provider \""+ProviderName+"\"");
   return factory;
}

public DbConnection GetConnection(String connectionName)
{
   //Get the connection string info from web.config
   ConnectionStringSettings cs = GetConnectionString(connectionName);

   //Get the factory for the given provider (e.g. "System.Data.SqlClient")
   DbProviderFactory factory = GetFactory(cs.ProviderName);


   //Have the factory give us the right connection object
   DbConnection conn = factory.CreateConnection();

   //Undefined behaviour if CreateConnection failed
   //Defensive test for null connection anyway
   if (conn == null)
      throw new Exception("Could not obtain connection from factory");

   //Knowing the connection string, open the connection
   conn.ConnectionString = cs.ConnectionString;
   conn.Open()

   return conn;
}

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

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