C# 开始、完成和失败方法中周围代码的设计模式

C# 开始、完成和失败方法中周围代码的设计模式,c#,design-patterns,C#,Design Patterns,假设我要运行不同的任意代码段,但在每个代码段之前,我必须运行Start()方法,然后在每个代码段之后,我需要运行Complete()方法。但是,如果在代码部分抛出异常,我希望运行Fail(字符串消息)方法,而不是Complete()。是否有一种设计模式可以优雅地封装它,使其整洁且易于重复 例如,假设我有一个名为Thing的类型,它包含一个Start()方法,该方法向日志数据库表中添加一行以反映任务正在进行中,一个Complete()方法更改该行以反映任务已完成和失败(字符串消息)更改行以反映任务

假设我要运行不同的任意代码段,但在每个代码段之前,我必须运行
Start()
方法,然后在每个代码段之后,我需要运行
Complete()
方法。但是,如果在代码部分抛出异常,我希望运行
Fail(字符串消息)
方法,而不是
Complete()
。是否有一种设计模式可以优雅地封装它,使其整洁且易于重复

例如,假设我有一个名为
Thing
的类型,它包含一个
Start()
方法,该方法向日志数据库表中添加一行以反映任务正在进行中,一个
Complete()
方法更改该行以反映任务已完成和
失败(字符串消息)
更改行以反映任务失败的方法。不过,这些只是示例,它们可以执行任何设置和整理类型的任务

简单的实现可能只是手动调用这些方法:

public void DoStuff()
{
    var thing = new Thing();
    thing.Start();
    try
    {
        DoImportantStuff();
        thing.Complete();
    }
    catch (Exception e)
    {
        thing.Fail(e.Message);
    }
}
但是如果我不得不在很多不同的地方重复这一点,它最终会产生相当多的重复,可能很容易忘记调用
Complete
,或者以某种微妙的方式将其搞糟

在C#中,有
使用
模式,它提供了一种封装大部分内容的好方法。例如,如果我的
东西
类型如下所示:

public class Thing : IDisposable
{
    public Thing(){
        Start();
    }

    private void Start() { /* start */ }
    private void Complete() { /* complete */ }

    public void Dispose()
    {
        Complete();
    }
}
public class Thing 
{
  private void Start() { /* start */ }
  private void Complete() { /* complete */ }
  private void Fail(string message) {}

  public void DoAction(Action action)
  {
      this.Start();
      try 
      {
        action();
        this.Complete();
      }
      catch (Exception e)
      {
        this.Fail(e.Message);
      }

  }
}
Thing thing = new Thing();
thing.DoAction(this.DoStuff);
我的
DoStuff()
方法现在可以简化为:

public void DoStuff()
{
    using(new Thing())
    {
        DoImportantStuff();
    }
}
这是更好的。但是如果抛出异常,它不允许调用
Fail
而不是
Complete
,因为(我想!)实际上是在
Finally
块中调用
Dispose
方法

我曾想过在
using
块中设置一个
try/catch
,然后在
catch
块中设置一个
东西。hasfiled
标志,然后在
Dispose
方法中使用它来决定是
完成
还是
失败
。但这似乎有点棘手,我希望
东西的消费者必须尽可能少地做一些事情,使其正常工作


那么,是否有一种设计模式可以封装我想要做的事情,并避免每次都需要手动编写
try\catch

public class Thing : IDisposable
{
    public Thing(){
        Start();
    }

    private void Start() { /* start */ }
    private void Complete() { /* complete */ }

    public void Dispose()
    {
        Complete();
    }
}
public class Thing 
{
  private void Start() { /* start */ }
  private void Complete() { /* complete */ }
  private void Fail(string message) {}

  public void DoAction(Action action)
  {
      this.Start();
      try 
      {
        action();
        this.Complete();
      }
      catch (Exception e)
      {
        this.Fail(e.Message);
      }

  }
}
Thing thing = new Thing();
thing.DoAction(this.DoStuff);
然后像这样使用它:

public class Thing : IDisposable
{
    public Thing(){
        Start();
    }

    private void Start() { /* start */ }
    private void Complete() { /* complete */ }

    public void Dispose()
    {
        Complete();
    }
}
public class Thing 
{
  private void Start() { /* start */ }
  private void Complete() { /* complete */ }
  private void Fail(string message) {}

  public void DoAction(Action action)
  {
      this.Start();
      try 
      {
        action();
        this.Complete();
      }
      catch (Exception e)
      {
        this.Fail(e.Message);
      }

  }
}
Thing thing = new Thing();
thing.DoAction(this.DoStuff);
使用

该模式称为“模板方法”。您可以在标题“面向方面编程”下找到您的实现。
()

这实际上并不是对所问问题的回答。虽然这可能不是一种设计模式,但我认为这很容易成为具有一流函数的语言中最优雅的解决方案,因此我将其标记为已接受。在没有函数传递的语言中,我想模板方法模式是最好的选择如果你要链接到某个东西,请在你的实际答案中包含一个代码示例,因为链接可能会过期。提及模板方法模式很好,尽管我不确定该链接是否有用,因为它没有明确讨论模板模式,并且在web服务细节方面有点陷入困境。wikipedia的文章()提供了一个更好的总结:“在软件工程中,模板方法模式是一种行为设计模式,它定义了操作中算法的程序框架,将某些步骤推迟到子类。它允许在不改变算法结构的情况下重新定义算法的某些步骤。”看看面向方面编程()。看起来您可以将entry/error/leave方法定义为连接点。