重复位代码的设计模式/ C#技巧

AJM*_*AJM 10 .net c# asp.net wcf logging

我有一个WCF服务,它记录任何异常,然后将它们作为FaultExceptions抛出.

我正在做很多重复,例如在每种服务方法中.

try { 
   // do some work

}
catch(Exception ex)
{
  Logger.log(ex);

  // actually will be Fault Exception but you get the idea.
  throw ex;
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种更优雅的方式,因为我正在切割和粘贴每个服务中的try/catch.

是否有一个设计模式/ C#技巧可以用来使这更优雅?

Nic*_*ler 9

你在谈论AOP - Aspect Oriented Programming

这是我如何通过将"工作"作为lambda传递来实现的:

public partial static class Aspect
{
  public static T HandleFaultException<T>( Func<T> fn )
  {
    try
    { 
      return fn();
    }
    catch( FaultException ex )
    {
      Logger.log(ex);
      throw;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

return Aspect.HandleFaultException( () =>
  {
    // call WCF
  }
);
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以实现相同的目标,甚至是一些商业产品,但我发现这种方式是最明确和最灵活的.

例如,您可以编写一个方面来为您创建和配置客户端:

public partial static class Aspect
{
  public static T CallClient<T>( Func<Client, T> fn )
  {
    using ( var client = ... create client ... )
    {
      return fn( client );
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以:

return Aspect.CallClient( client =>
  {
    return client.Method( ... );
  }
);
Run Code Online (Sandbox Code Playgroud)

然后,您可以包装您通常想要应用的所有方面并创建一个主方面.


mel*_*okb 5

我们的一个WCF服务中存在类似的问题,我通过使用帮助程序委托解决了这个问题:

public static void ErrorHandlingWrapper(Action DoWork)
{
    try { 
        DoWork();
    }
    catch(Exception ex)
    {
        Logger.log(ex);

        // actually will be Fault Exception but you get the idea.
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

public void MyMethod1()
{
    ErrorHandlingWrapper(() => {
        // do work
    });
}

public void MyMethod2()
{
    ErrorHandlingWrapper(() => {
        // do work
    });
}
Run Code Online (Sandbox Code Playgroud)

您仍然需要重复包装器,但这样的代码要少得多,您可以try..catch在一个地方修改逻辑.


Den*_*nko 1

模板方法模式就是这样做的,您可以使用 C# 的委托(或 lambda)轻松实现它,而无需继承。