سؤال

ما هو أفضل الممارسات عند إرجاع البيانات من الوظائف.أنه من الأفضل أن تعود فارغة أو فارغة الكائن ؟ و لماذا ينبغي للمرء أن لا أحد على الآخر ؟

النظر في هذا:

public UserEntity GetUserById(Guid userId)
{
     //Imagine some code here to access database.....

     //Check if data was returned and return a null if none found
     if (!DataExists)
        return null; 
        //Should I be doing this here instead? 
        //return new UserEntity();  
     else
        return existingUserEntity;
}

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

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

المحلول

وبالعودة لاغية عادة ما تكون أفضل فكرة إذا كنت تنوي تشير إلى أن لا توجد بيانات متاحة.

وكائن فارغ يعني تم إرجاع البيانات، في حين يعود لاغية واضح يشير إلى أن شيئا لم عاد.

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

نصائح أخرى

وذلك يعتمد على ما تروق لقضيتك.

هل يعقل أن يعود لاغية، على سبيل المثال "لا يوجد مثل هذا المستخدم"؟

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

وأو أنه لا معنى لرمي استثناء (على غرار "FileNotFound") إذا كان رمز الدعوة يطالب المستخدم مع معرف غير صالح؟

ولكن - من فصل الاهتمامات / جهة نظر SRP، الأولين هي الأصح. و<م> من الناحية الفنية الأول هو الراجح (ولكن فقط عن طريق الشعر) - GetUserById يجب أن تكون مسؤولة فقط لشيء واحد - الحصول على المستخدم. التعامل مع الخاص "المستخدم غير موجود" حالة بالعودة شيء آخر يمكن أن يكون انتهاكا لSRP. فصل في الاختيار مختلفة - أن bool DoesUserExist(id) يكون مناسبا إذا كنت قد اخترت لرمي استثناء

<القوي> بناء على تعليقات واسعة أدناه : إذا هذا هو السؤال التصميم على مستوى API، يمكن أن تكون هذه الطريقة مشابهة ل"OpenFile" أو "ReadEntireFile". نحن "فتح" مستخدم من بعض مستودع وترطيب الكائن من البيانات الناتجة. استثناء <م> يمكن أن تكون المناسب في هذه الحالة. قد لا يكون، ولكن يمكن أن يكون.

وجميع المناهج مقبولة - أنها تعتمد فقط، استنادا إلى السياق الأوسع لAPI / التطبيق.

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

إذا نوع عودتك صفيف ثم بإرجاع مجموعة فارغة على خلاف ذلك يعود لاغية.

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

لسلاسل، المصفوفات ومجموعات الوضع عادة ما يكون مختلفا. أتذكر شكل التوجيهي MS أن أساليب يجب أن يقبل null كقائمة 'فارغة' ولكن عودة مجموعات من طول الصفر بدلا من null. الشيء نفسه بالنسبة لسلاسل. لاحظ أنه يمكنك يعلن صفائف فارغة: int[] arr = new int[0];

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

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

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

وتحرير: (لمعالجة تعليق من آدم في إجابة أخرى)

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

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

وأنا شخصيا سيعود لاغية، لأن هذه هي الطريقة التي أتوقع أن DAL / طبقة مستودع للعمل.

إذا لم يكن موجودا، لا يعود أي شيء يمكن أن يفسر على أنه بنجاح جلب كائن، null يعمل بشكل جميل هنا.

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

أنا أميل إلى

  • return null إذا كان معرف كائن لا وجود له عندما لا يعرف مسبقا ما إذا كان يجب أن موجودة.
  • throw إذا كان معرف كائن لا وجود له عندما يجب أن موجودة.

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

Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
    if (InternalIdExists(id))
    {
        o = InternalGetSomeObject(id);

        return true;
    }
    else
    {
        return false;
    }
}

الثانية:

SomeObject FindSomeObjectById(Int32 id)
{
    SomeObject o;

    return TryGetObjectById(id, out o) ? o : null;
}

الثالث:

SomeObject GetSomeObjectById(Int32 id)
{
    SomeObject o;

    if (!TryGetObjectById(id, out o))
    {
        throw new SomeAppropriateException();
    }

    return o;
}

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

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
}

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

public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
    else
        notFound(); // or notFound.Call();
}

والنهج نفسه باستخدام كائن واحد قد تبدو مثل:

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback.Found(userEntity);
    else
        callback.NotFound();
}

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

نستخدم CSLA.NET ، وترى أن فشل في جلب البيانات يجب أن تعود "فارغة" الكائن.هذا هو في الواقع مزعج جدا ، كما أنه مطالب الاتفاقية من التحقق من ما إذا كان obj.IsNew rathern من obj == null.

السابقة ملصق المذكورة ، null عودة القيم سوف يسبب رمز تفشل مباشرة ، مما يقلل من احتمال الشبح المشاكل التي تسببها فارغة الكائنات.

شخصيا, أعتقد null هو أكثر أناقة.

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

يمكنك معالجة هذا عن طريق:

if (User.Exists(id)) {
  this.User = User.Fetch(id);
} else {
  Response.Redirect("~/notfound.aspx");
}

لكن إضافية الدعوة إلى قاعدة البيانات في كل مرة ، والتي قد تكون قضية على المرور صفحات.في حين أن:

this.User = User.Fetch(id);

if (this.User == null) {
  Response.Redirect("~/notfound.aspx");
}

...يتطلب مكالمة واحدة فقط.

وأنا أفضل null، لأنه متوافق مع المشغل خالية التحام (??).

أنا أقول العودة فارغة بدلا من كائن فارغ.

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

هذه هي القاعدة عموما أنا متابعة:

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

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

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

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

وتحرير:

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

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

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

في كائنات الأعمال لدينا لدينا 2 طرق الحصول رئيسية هي:

لابقاء الامور بسيطة في سياق أو على سؤالك أنها ستكون:

// Returns null if user does not exist
public UserEntity GetUserById(Guid userId)
{
}

// Returns a New User if user does not exist
public UserEntity GetNewOrExistingUserById(Guid userId)
{
}

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

وهذا يتيح لنا أن يكون أفضل من كلا العالمين في سياق آخر، حيث يتم استخدامها.

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

وباستخدام Java، يطلب منا لإضافة assert exists(object) : "You shouldn't try to access an object that doesn't exist"; في بداية أي طريقة يمكن أن يعود لاغية، للتعبير عن "شروط مسبقة" (لا أعرف ما هي الكلمة في اللغة الإنجليزية).

وIMO هذا في الحقيقة ليست سهلة الاستخدام ولكن هذا ما أنا باستخدام، والانتظار لشيء أفضل.

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

public Option<UserEntity> GetUserById(Guid userId)
{
 //Imagine some code here to access database.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return Option<UserEntity>.Nothing; 
 else
    return Option.Just(existingUserEntity);
}

وأن تستخدم مثل هذا:

Option<UserEntity> result = GetUserById(...);
if (result.IsNothing()) {
    // deal with it
} else {
    UserEntity value = result.GetValue();
}

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

وأنا عادة تعود فارغة. كما أنه يوفر آلية سريعة وسهلة للكشف إذا كان هناك شيء ثمل دون رمي الاستثناءات واستخدام طن من حاول / catch في كل مكان.

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

وباستخدام نمط NullObject هذا من شأنه أن يكون: -

public UserEntity GetUserById(Guid userId)

{      // تخيل بعض التعليمات البرمجية هنا للوصول إلى قاعدة بيانات .....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return new NullUserEntity(); //Should I be doing this here instead? return new UserEntity();  
 else
    return existingUserEntity;

و}

class NullUserEntity: IUserEntity { public string getFirstName(){ return ""; } ...} 

أن أضع ما قال آخرون في pithier الطريقة...

الاستثناءات هي ظروف استثنائية

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

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

الآن, إذا كان لدي بعض رمز الدخول التي تحققت ضد موفر LDAP ثم فحص ضد DB للحصول على مزيد من التفاصيل و كنت أتوقع هذه يجب أن تكون متزامنة في جميع الأوقات ، قد إرم الاستثناء ثم.كما قال آخرون إنها قواعد العمل.

الآن أنا أقول هذا هو العامة القاعدة.هناك أوقات حيث كنت قد ترغب في كسر هذا.بيد أن تجربتي و تجارب مع C# (الكثير من) و جافا(شيئا من ذلك) علمتني أن كثيرا أكثر تكلفة أداء الحكمة للتعامل مع الاستثناءات من التعامل مع التنبؤ بها القضايا عبر المنطق الشرطي.أنا أتحدث تصل إلى 2 أو 3 أوامر من حجم أكثر تكلفة في بعض الحالات.لذا, إذا كان من الممكن التعليمات البرمجية الخاصة بك يمكن أن ينتهي في حلقة ، ثم أنصح تعود فارغة و اختبار ذلك.

واغفر لي الزائفة فب / الرمز.

واعتقد ان ذلك يتوقف حقا على الاستخدام المقصود من النتيجة.

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

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

مثال:

function saveTheRow($prim_key, $data) {
    $row = getRowByPrimKey($prim_key);

    // Populate the data here

    $row->save();
}

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

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

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

مثال:

function displayData($row_id) {
    // Logging of the error would happen in this function
    $row = getRow($row_id);
    if($row === null) {
        // Handle the error here
    }

    // Do stuff here with data
}

function getRow($row_id) {
 $row = null;
 try{
     if(!$db->connected()) {
   throw excpetion("Couldn't Connect");
  }

  $result = $db->query($some_query_using_row_id);

  if(count($result) == 0 ) {
   throw new exception("Couldn't find a record!");
  }

  $row = $db->nextRow();

 } catch (db_exception) {
  //Log db conn error, alert admin, etc...
  return null; // This way I know that null means an error occurred
 }
 return $row;
}

وهذا هو بلدي القاعدة العامة. انها عملت بشكل جيد حتى الآن.

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

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

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

مثال:

bool IsAdministrator(User user)
{
    var groupsOfUser = GetGroupsOfUser(user);

    // This foreach would cause a run time exception if groupsOfUser is null.
    foreach (var groupOfUser in groupsOfUser) 
    {
        if (groupOfUser.Name == "Administrators")
        {
            return true;
        }
    }

    return false;
}

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

وأيضا، يجب أن مثل هذه الأساليب التي يمكن أن تعود أي نتيجة تشير إلى أنه من خلال اسمهم. أضع عادة حاول أو TryGet أو TryFind في بداية اسم الوسيلة في إشارة إلى أنه قد بإرجاع نتيجة فارغة (على سبيل المثال TryFindCustomer، TryLoadFile، الخ.).

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

وهنا مثال آخر حيث يتم استخدام الخيار بدلا من اغية عودته للحد كود التعقيد: <لأ href = "http://www.codinghelmet.com/؟path=howto/reduce-cyclomatic-complexity-option-functional- اكتب "يختلط =" نوفولو "> كيفية الحد من التعقيد Cyclomatic: الخيار الوظيفي نوع

والمزيد من اللحوم لطحن: دعنا نقول بلدي DAL بإرجاع NULL لGetPersonByID كما نصحت من قبل بعض. ما ينبغي أن تفعله بلدي (رقيقة نوعا ما) BLL إذا تلقت NULL؟ تمرير ذلك NULL على ما يصل، والسماح للقلق نهاية المستهلك حيال ذلك (في هذه الحالة، صفحة ASP.Net)؟ ماذا عن وجود BLL رمي استثناء؟

ووBLL يمكن أن تستخدم من قبل ASP.Net واربح التطبيقات، أو مكتبة أخرى الفئة - أعتقد أنه ليس من العدل أن نتوقع من المستهلك النهائي لجوهرها "يعرف" أن طريقة GetPersonByID ترجع فارغة (ما لم يتم استخدام أنواع فارغة ، أعتقد).

وبلدي يأخذ (ما يستحق) هو أن بلدي DAL بإرجاع NULL إذا وجدت شيئا. FOR بعض الكائنات، وهذا موافق - يمكن أن يكون 0: قائمة طويلة من الأشياء، لذلك عدم وجود أي شيء على ما يرام (على سبيل المثال قائمة الكتب المفضلة لديك). في هذه الحالة، يعود لي BLL قائمة فارغة. بالنسبة لمعظم الأشياء كيان واحد (على سبيل المثال، المستخدم، حساب، فاتورة) إذا كنت لا تملك واحدة، فإن ذلك بالتأكيد مشكلة ورمي استثناء مكلفة. ومع ذلك، كما نرى استرداد المستخدم عن طريق معرف فريد وهذا ما أعطيت من قبل التطبيق يجب دائما إرجاع المستخدم، والاستثناء هو استثناء "السليم"، كما هو الحال في انها استثنائية. المستهلك النهائي من BLL (ASP.Net، f'rinstance) تتوقع فقط من أي وقت مضى أن تكون الأمور مرضيا، دوري، لذلك سيتم استخدام استثناء غير معالج معالج بدلا من التفاف كل مكالمة واحدة إلى GetPersonByID في محاولة - كتلة الصيد

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

وأنا أستمتع هذا المنصب، والكثير من الاقتراحات الجيدة ل "الامر يتوقف" سيناريوهات: -)

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

وسيكون هناك كمية كبيرة من بنود حارس علاج if (f() != null) إشارة لاغية.

ما هو null، هو إجابة مقبولة أو مشكلة؟ هي لاغية حالة صالحة لكائن معين؟ (تخيل أنك عميل لرمز). أعني كل أنواع مرجع يمكن أن تكون فارغة، ولكن يفعلون ذلك؟

وبعد null التسكع سوف تعطي دائما تقريبا وجود استثناءات قليلة NullRef غير متوقعة من وقت لآخر كما ينمو أكواد قاعدة.

وهناك بعض الحلول، tester-doer pattern أو تنفيذ option type من البرمجة الوظيفية.

وأنا في حيرة في عدد من الأجوبة (في جميع أنحاء الشبكة) أن أقول لك حاجة طريقتين: طريقة "IsItThere ()" وطريقة "GetItForMe ()" وحتى هذا يؤدي إلى حالة تعارض. ما هو الخطأ في دالة تقوم بإرجاع اغية، وإسناد ذلك إلى متغير، والتحقق من متغير لاغية كل في اختبار واحد؟ وقد يتخلله قانون بلدي C السابق مع

وإذا (NULL! = (متغير = وظيفة (الحجج ...))) {

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

وأنا أتفق مع معظم الوظائف هنا ، والتي تميل نحو null.

بلدي المنطق أن توليد كائن فارغ مع غير nullable خصائص قد يسبب الخلل.على سبيل المثال, كيان مع int ID الملكية سيكون لها قيمة أولية من ID = 0, الذي هو تماما قيمة صالحة.أن هذا الكائن تحت بعض الظروف ، على حفظها في قاعدة بيانات ، سيكون شيئا سيئا.

عن أي شيء مع التكرار سوف دائما استخدام فارغة جمع.شيء مثل

foreach (var eachValue in collection ?? new List<Type>(0))

هو رمز رائحة في رأيي.جمع خصائص يجب ألا تكون فارغة أبدا.

ميزة القضية String.ويقول كثير من الناس ، String.IsNullOrEmpty ليس ضروريا حقا ، ولكن لا يمكن دائما التمييز بين سلسلة فارغة null.علاوة على ذلك, بعض أنظمة قواعد البيانات (أوراكل) لا يميز بينهما في كل شيء ('' يحصل المخزنة DBNULL), لذلك كنت اضطر إلى التعامل معها على قدم المساواة.والسبب في ذلك هو أن معظم قيم السلسلة تأتي إما من إدخال المستخدم أو من الأنظمة الخارجية في حين لا مربعات النص ولا أكثر الصرف صيغ مختلفة لتمثيل '' و null.حتى إذا كان المستخدم يريد إزالة قيمة, وقال انه لا يمكن أن تفعل أي شيء أكثر من تطهير تحكم الإدخال.كما تميزت nullable وغير nullable nvarchar حقول قاعدة البيانات هو أكثر من تساؤل ، إذا DBMS لا أوراكل - حقل إلزامي التي تسمح '' غريب واجهة المستخدم الخاصة بك لن تسمح بذلك ، لذلك القيود الخاصة بك لا خريطة.لذا فإن الإجابة هنا في رأيي هو التعامل معها على قدم المساواة ، دائما.

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

وهو غير متزامن TryGet نمط:

متزامن الطرق ، وأعتقد @يوهان Gerell هو الجواب هو على نمط استخدام في جميع الحالات.

ومع ذلك TryGet نمط مع out المعلمة لا يعمل مع المتزامن الأساليب.

مع C# 7 Tuple حرفية يمكنك الآن القيام بذلك:

async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

        return (true, o);
    }
    else
    {
        return (false, default(SomeObject));
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top