2016-08-15 11 views
0

私はベース "例外ハンドラ"のようなものを作ろうとしています。したがって、この基本クラスは、派生クラス内の任意の数のパラメータを持つ任意のメソッドが呼び出されると、を試行します。私はここで、言葉でこれを記述する際によくないよシナリオです:キャッチ派生クラス異なるメソッドと引数を持つ基本クラスの例外

public abstract BaseClass 
{ 
    Exception _ex; 

    public Exception LastKnownException 
    { 
     get 
     { 
      return this._ex; 
     } 
    } 

    //... 
    //what do I do here to assign the value of above property when some random exception occur in derived class? 
    //... 

    //The closest I can get... 
    public void RunMethod(Action method) 
    { 
     try 
     { 
      method.Invoke(); 
     } 
     catch (Exception ex) 
     { 
      this._ex = ex; 
     } 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    public void DoRandomMethod(int couldBeOfAnyTypeHere, bool andIndefiniteNumberOfThese) 
    { 
     bool result = false; 
     var someObject = new OtherClass(couldBeOfAnyTypeHere, out andIndefiniteNumberOfThese); 

     someObject.DoInternalWork(result); // <-- here is where I need the base class to take care if any exception should occur 
    } 

    public int AnotherMethod(int? id) 
    {  
     if (!id.HasValue) 
      id = Convert.ToInt32(Session["client_id"]); 

     var someOtherObject = new OtherClassB(id.Value); 

     return someOtherObject.CheckSomething(); // <-- and catch possible exceptions for this one too 
    } 

    //The closest I can get... (see base class implementation) 
    public List<RandomClass> GetSomeListBy(int id) 
    { 
     RunMethod(() => 
      string[] whateverArgs = new[] { "is", "this", "even", "possible?" }; 

      YetAnotherStaticClass.GetInstance().ExecuteErrorProneMethod(whateverArgs); // <-- Then when something breaks here, the LastKnownException will have something 
     ); 
    } 
} 

public class TransactionController : Controller 
{ 
    public ActionResult ShowSomething() 
    { 
     var dc = new DerivedClass(); 

     dc.DoRandomMethod(30, true); 

     if (dc.LastKnownException != null) 
     { 
      //optionally do something here 
      return RedirectToAction("BadRequest", "Error", new { ex = dc.LastKnownException }); 
     } 
     else 
     { 
      return View(); 
     }  
    } 
} 

EDIT:私の単純なアプローチは動作しますが、唯一、私はこのラムダとのすべてのメソッドをラップする必要がありますする必要はありません-driven RunMethod()メソッドは常にあります - 何らかの着信例外を傍受し、エラーをスローせずにExceptionオブジェクトを派生クラスに戻すために基本クラスが必要です。

任意のアイデアをいただければ幸いです。そして、事前に感謝!

+0

あなたのご質問はありますか? – Ouarzy

答えて

1

私はあなたが、例外が処理されないことを発生するたびに、このイベントが発生しますイベントにSystem.AppDomain.UnhandledException

を使用することを検討すべきだと思います。

例外が発生する可能性のあるコードを混乱させないので、コードははるかに読みやすくなります。それ以外にも、派生クラスには例外をキャッチする機会が与えられます。自動例外キャッチャーに干渉することなく、例外をキャッチできます。

あなたの派生クラスのいくつかの関数を呼び出して、例外があるかどうかを呼び出し元が例外を引き起こした関数を知らないかどうかを調べるような設計です。私はあなたの呼び出し元が実際にどの関数が例外を引き起こすのか興味がないと仮定します。これは通常、誰かが調査するまで例外を記録するだけの場合です。

それは場合には、次のような何かを行うことを検討されている場合:

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 
} 

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    var ex = e.ExceptionObject as Exception; 
    if (ex != null) 
     logger.LogException(ex); 
    // TODO: decide whether to continue or exit. 
} 

あなたが本当にあなただけの抽象基底クラスの

public abstract BaseClass 
{ 
    private List<Exception> unhandledExceptions = new List<Exception>(); 

    protected BaseClass() 
    { 
     AppDomain.CurrentDomain.UnhandledException += UnhandledException; 
    } 

private void UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    var ex = e.ExceptionObject as Exception; 
    if (ex != null) 
     this.UnhandledExceptions.Add(ex); 
} 

public List<Exception> LastKnownExceptions 
{ 
    get { return this.unhandledExceptions; } 
} 
+0

この 'AppDomain.UnhandledException'は私には新しく、私は間違いなくそれを調べます!ありがとう!しかし、あなたの "呼び出された関数が例外を引き起こした関数を知らない"場合、おそらく私はいくつかのカスタムクラスを使用してこの例外の詳細を保持します。 – jom

+0

私は1つの質問を持っています:この 'BaseClass'がコンストラクタで初期化されているので、複数のクラスから派生した場合、グローバルイベントハンドラは常にリセットされますか?または置き換えられますか? – jom

+0

あなたはあなたが望むものを例外と共に書いていませんでした。例外を引き起こした呼び出しや、いくつかの例外を処理するメソッドを検出する仕組みがなかったので、多分やりたいと思わなかった、多分ロギングしていたと思われるので、例外なく何かをしたい。彼らの出現が例外的であると確信していますか?そうでない場合:戻り値を考慮する。例外の場合、例外はクラス全体のプロパティか、例外はあなたが呼び出した関数に属していますか?それが関数に属している場合、それをなぜクラスの一部として設計するのですか? –

1

これを行うにしたい場合は、私は引くための同様の要件を持っていました例外処理をカプセル化するために特定の実装(つまり、抽象クラスではない)を使用していました。

これは予想される例外(params [] catchableExceptionTypes)の引数を取りますが、もちろん自分の要件に合わせて変更することができます。

public class ExceptionHandler 
{ 
    // exposes the last caught exception 
    public Exception CaughtException { get; private set; } 

    // allows a quick check to see if an exception was caught 
    // e.g. if (ExceptionHandler.HasCaughtException) {... do something...} 
    public bool HasCaughtException { get; private set; } 

    // perform an action and catch any expected exceptions 
    public void TryAction(Action action, params Type[] catchableExceptionTypes) 
    { 
     Reset(); 
     try 
     { 
      action(); 
     } 
     catch (Exception exception) 
     { 
      if (ExceptionIsCatchable(exception, catchableExceptionTypes)) 
      { 
       return; 
      } 
      throw; 
     } 
    } 

    // perform a function and catch any expected exceptions 
    // if an exception is caught, this returns null 
    public T TryFunction<T>(Func<T> function, params Type[] catchableExceptionTypes) where T : class 
    { 
     Reset(); 
     try 
     { 
      return function(); 
     } 
     catch (Exception exception) 
     { 
      if (ExceptionIsCatchable(exception, catchableExceptionTypes)) 
      { 
       return null; 
      } 
      throw; 
     } 
    } 

    bool ExceptionIsCatchable(Exception caughtException, params Type[] catchableExceptionTypes) 
    { 
     for (var i = 0; i < catchableExceptionTypes.Length; i++) 
     { 
      var catchableExceptionType = catchableExceptionTypes[i]; 
      if (!IsAssignableFrom(caughtException, catchableExceptionType)) continue; 
      CaughtException = caughtException; 
      HasCaughtException = true; 
      return true; 
     } 
     return false; 
    } 

    static bool IsAssignableFrom(Exception exception, Type type) 
    { 
     if (exception.GetType() == type) return true; 
     var baseType = exception.GetType().BaseType; 
     while (baseType != null) 
     { 
      if (baseType == type) return true; 
      baseType = baseType.BaseType; 
     } 
     return false; 
    } 

    void Reset() 
    { 
     CaughtException = null; 
     HasCaughtException = false; 
    } 
} 
+0

あなたのソリューションを共有してくれてありがとう!しかし、最後の編集を見逃した場合は、「このラムダ駆動のメソッドですべてのメソッドを常にラップする必要はありません。何らかの着信例外を傍受してExceptionオブジェクトをエラーをスローせずに派生クラスを生成します。 " – jom

関連する問題