• 泛型委托在项目中的应用


         感悟:对泛型委托基本属于有点认识,但从来没真正在项目中使用过,有时感觉没有合适的场景应用,但看了artech兄的文章,我才明白,原来泛型委托真的可以做很多事情,而且效果往往是没有使用委托所达不到的。

        Action<T> 泛型委托:封装一个方法,该方法只采用一个参数并且不返回值。可以使用此委托以参数形式传递方法,而不用显式声明自定义的委托。该方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能返回值。当然泛型委托不只是只能支持一个参数,它最多可以支持四个参数。  

       泛型委托与直接显示声明自定义委托的示例比较:

    1:显示声明自定义委托:

    代码
    delegate void DisplayMessage(string message);
    public class TestCustomDelegate
    {
       
    public static void Main()
       {
          DisplayMessage messageTarget; 
          messageTarget 
    = ShowWindowsMessage;
          messageTarget(
    "Hello, World!");   
       }      
       
    private static void ShowWindowsMessage(string message)
       {
          MessageBox.Show(message);      
       }
    }

      

     2: Action<T> 用法。比起自定义委托,明显可以看出代码简洁了。

    代码
    public class TestAction1
    {
       
    public static void Main()
       {
          Action
    <string> messageTarget; 
         messageTarget 
    = ShowWindowsMessage;
          messageTarget(
    "Hello, World!");   
       }      
       
    private static void ShowWindowsMessage(string message)
       {
          MessageBox.Show(message);      
       }
    }

     

        Func<T, TResult> 委托:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。同理,这里的泛型委托只是接受一个参数的委托,它最多同样支持四个参数。TResult:此委托封装的方法的返回值类型。


        问题:目前本公司在写程序时,都使用了log4net,我想大家在做异常时,都会利用try catch来捕获异常,日志就在catch块中完成,但每个方法都写一堆的try catch往往显的有点别扭。虽然写程序时提倡尽量去捕获具体的错误异常,但总会有你预想不到的异常抛出,为此直接捕获Exception算是不错的做法。

        具体场景:在客户端调用WCF服务时,我们都需要在客户做异常处理,最常见的错误异常为CommunicationException,TimeoutException,Exception示例如下:

                

    代码
    try
                {
                    
    //执行方法调用 
                    ......
                    (proxy 
    as ICommunicationObject).Close();
                }
                
    catch (CommunicationException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();

                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常CommunicationException:" + ex.ToString());
                }
                
    catch (TimeoutException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据超时TimeoutException:" + ex.ToString());
                }
                
    catch (Exception ex)
                {      
                    (proxy 
    as ICommunicationObject).Close();      
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常Exception:" + ex.ToString());
                }

      

          但如果这种代码遍布整个项目,我想就有重构的必要了,因为项目中最好不要出现类似复制的代码出现,为此我们可以采用Invoke形式来重构我们已有代码,下面给出两个方法,一个是没有返回值的,一个是有值的。
        

    代码
    public static void Invoke<TContract>(TContract proxy, Action<TContract> action)
            {
                
    try
                {
                    action(proxy);
                    (proxy 
    as ICommunicationObject).Close();
                }
                
    catch (CommunicationException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常CommunicationException:" + ex.ToString());
                }
                
    catch (TimeoutException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据超时TimeoutException:" + ex.ToString());
                }
                
    catch (Exception ex)
                {        
                    (proxy 
    as ICommunicationObject).Close();      
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常Exception:" + ex.ToString());
                }
            }
            
    public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func)
            {
                TReturn returnValue 
    = default(TReturn);
                
    try
                {
                    returnValue 
    = func(proxy);
                }
                
    catch (CommunicationException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();

                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常CommunicationException:" + ex.ToString());
                }
                
    catch (TimeoutException ex)
                {
                    (proxy 
    as ICommunicationObject).Abort();

                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据超时TimeoutException:" + ex.ToString());
                }
                
    catch (Exception ex)
                {
                    WebLog.SquareLog.CommonLogger.Error(
    "取积分广场首页酒店数据异常Exception:" + ex.ToString());
                }
                
    return returnValue;
            }

     

          如何调用:可以看出客户端代码已经变成一条简洁代码了,它即完成了完整的异常处理,而且也把所有能够捕获的异常信息记录下来。
          

    list = ErrorHandler.Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList()); 

     

         说明:至于Invoke的应用,在System .Runtime .Remoting.Proxies有一个RealProxy,可以称做真正代理,里面有IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)方法:只不过这里面没有应用泛型委托。
           

    代码
            // 返回结果:
            
    //     The message returned by the invoked method, containing the return value and
            
    //     any out or ref parameters.
            public abstract IMessage Invoke(IMessage msg);
  • 相关阅读:
    数据库调优2
    数据库调优
    SQL优化
    支付宝/阿里面试题
    Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 标签 《转载》
    《转载》struts旅程《2》
    《转载》struts旅程《1》
    jsp 自定义标签
    body-content取值的意义
    jsp页面中jstl标签详解
  • 原文地址:https://www.cnblogs.com/top5/p/1715371.html
Copyright © 2020-2023  润新知