Lambda来了很久了,他有许多特性。其中之一,可以说是一种快速撰写匿名委托/函数的语法吧。最近偶然拍脑袋,觉得可以用匿名委托来实现一下
ExceptionHandling,希望能得到轻量,可任意扩展,可重用的效果。所以特别撰写本文,望与诸君一起讨论一下,这种方式的实现究竟有无实际意义。

    首先看看我们平常使用的方式:   

尝试用Lambda表达式进行ExceptionHandlingtry
    }

     这种方式下,我们可以预先撰写一堆异常处理的策略已达到重用效果, 但实际使用上,这样做最大的缺点就是代码冗长不堪,相同的异常策略只能通过复制粘贴来重用,感觉非常石器:(


      我们再看看Exception Handling Application Block的方式:
try 
    { 
         
// Run code. 
    } 
    
catch(Exception ex) 
    {
         
bool rethrow = ExceptionPolicy.HandleException(ex, " Data Access Policy"); 
         
if (rethrow) 
         
throw
    }

     EHAB这种模式,写得可以简单很多, 但让人觉得不爽的是,由于直接先行Catch住Exception,若发现未处理的异常类型,就必需重抛异常。但这个重抛因为已经离开了事发地点,StackTrace等信息都不同了,给我们Debug带来困扰。

    我们现在有了匿名委托,其实要做一个这样的工具类,已经非常简单。首先构建一个简单得很的类如下:

class Try<TException> where TException : Exception
    {
        
public Action<object> FinallyAction { getset; }

        
public Action<TException> Handler { getset; }

        
public Exception Exception { getprivate set; }

        
public bool Execute(Action<object> action)
        {
            
try
            {
                action.Invoke(
null);
            }
            
catch (TException ex)
            {
                
this.Handler(ex);
                
this.Exception = ex;
            }
            
finally
            {
                
if (this.FinallyAction != null)
                    
this.FinallyAction(null);
            }

            
return this.Exception != null;
        }
    }

然后可以简单测试如下:

class Test
    {
        
public static void ABC()
        {
            Try
<NullReferenceException> Try = new Try<NullReferenceException>()
            {
                Handler 
= f => System.Windows.Forms.MessageBox.Show(f.Message),
                FinallyAction 
= f => System.Windows.Forms.MessageBox.Show("FinallyTest")
            };

            var ret 
= Try.Execute(f =>          //test1:
                {
                    
throw new NullReferenceException();
                });
            
if (!ret)
                
return;

            ret 
= Try.Execute(f =>          //test2
            {
                
throw new IndexOutOfRangeException();   //这里直接爆异常,因为并没有Handle这种类型
            });


        }
    }

 

      首个测试中,我们可以看到NullReferenceException成功地被Cacth了,而第二次测试,则原地爆出了异常。

      这个简单的类,基本具有了最基本的Try/Cacth块功能,只是。。。只是还不能支持同时Catch多个ExceptionType,要实现这个Feature,我们有很多办法,随 便想想至少3种:

    1, 写class Try<TException1, TException2>, class Try<TException1, TException2, TException3>...
        只要愿意,写六七十个的版本也可以。

    2, 使用Action,Func进行嵌套调用,即变形为:

 

try
        {
            
try
            {
                     coreWork();    
//核心代码
            }
            
catch (ExceptionType1 ex1)    //抓捕第一异常类型
            {
                 handleExceptionType1(ex1);                     
            }
    }
        cacth (ExceptionType2 ex2)     
//抓捕第二异常类型
        {
        handleExceptionType2(ex2);                         
        }

 

    3, 用Emit做DynamicMethod,这种应该最高效率。

    具体的实现我不在这里啰嗦了,目前是随手用第二种方式实现的。

 

    }

      使用的效果呢,如下: 

尝试用Lambda表达式进行ExceptionHandlingpublic partial class frmTryBlock : Form
}

    

     代码并未经过严格的测试,这里只是提出这一种思路和做法,我不奢望他能完全替代Try/Cacth,只是希望在很多需要重复使用的场合,可以利用他来简单快捷的撰写安全的代码。
   
    从效率而言,如果这个思路是可行的,我觉得肯定要换成Emit实现的版本。另外,这种方式也应该可以很方便地和EHAB一起使用。

    希望各位朋友不吝赐教:)


 

相关文章:

  • 2021-06-10
  • 2021-12-02
  • 2022-12-23
  • 2022-12-23
  • 2021-12-02
  • 2021-05-20
  • 2021-07-14
  • 2021-08-27
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-04-29
  • 2022-01-07
  • 2021-12-28
  • 2022-03-03
  • 2022-01-23
相关资源
相似解决方案