سؤال

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

ما هو أفضل:

public int DoSomething(string a)
{
     // might throw an exception
}
public bool TrySomething(string a, out result)
{
    try
    {
        result = DoSomething(a)
        return true;
    }
    catch (Exception)
    {
        return false;
    }

أو

public int DoSomething(string a)
{
     int result;
     if (TrySomething(a, out result))
     {
         return result;
     }
     else
     {
         throw Exception(); // which exception?
     }
}
public bool TrySomething(string a, out result)
{
    //...
}

وكنت تحمل غريزي أن المثال الأول هو الأصح (أنت تعرف بالضبط أي استثناء حدث)، ولكن لا يمكن أن حاول / catch تكون مكلفة للغاية؟ هل هناك طريقة لجذب الاستثناء في المثال الثاني؟

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

المحلول

وجعل TrySomething مجرد التقاط وابتلاع الاستثناء هو فكرة سيئة حقا. نصف نقطة من نمط TryXXX هو تجنب ضرب أداء الاستثناءات.

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

public int DoSomething(string input)
{
    int ret;
    Exception exception = DoSomethingImpl(input, out ret);
    if (exception != null)
    {
        // Note that you'll lose stack trace accuracy here
        throw exception;
    }
    return ret;
}

public bool TrySomething(string input, out int ret)
{
    Exception exception = DoSomethingImpl(input, out ret);
    return exception == null;
}

private Exception DoSomethingImpl(string input, out int ret)
{
    ret = 0;
    if (input != "bad")
    {
        ret = 5;
        return null;
    }
    else
    {
        return new ArgumentException("Some details");
    }
}

والوقت هذا قبل أن تلتزم أنه على الرغم من!

نصائح أخرى

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

public object DoSomething(object input){
  return DoSomethingInternal(input, true);
}

public bool TryDoSomething(object input, out object result){
  result = DoSomethingInternal(input, false);
  return result != null;
}

private object DoSomethingInternal(object input, bool throwOnError){
  /* do your work here; only throw if you cannot proceed and throwOnError is true */
}

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

هل يمكن تغيير TrySomething لتبدو وكأنها أدناه.

public bool TrySomething(string a, out result, bool throwException)
{
  try
  {
    // Whatever
  }
  catch
  {
    if(throwException)
    {
      throw;
    }
    else
    {
      return false;
    }
  }

}

public bool TrySomething(string a, out result)
{
  return TrySomething(a, out result, false);
}

وحتى تنفيذ DoSomething ستبدو

public int DoSomething(string a)
{
  int result;

  // This will throw the execption or 
  // change to false to not, or don't use the overloaded one.
  TrySomething(a, out result, true) 

  return result;      
}

إذا كنت لا تريد TrySomething مع throwException يتعرض للجمهور يمكنك جعله عضو خاص.

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

وعلى افتراض هذا هو C #، وأود أن أقول المثال الثاني

public bool TrySomething(string a, out result)
{
    try
    {
        result = DoSomething(a)
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

وأنه يحاكي بني في int.TryParse(string s, out int result)، وفي رأيي أفضل على البقاء بما يتفق مع اللغة / البيئة.

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