如何为一个方法实现前置条件?

3

我有一个类

public class MyService  
{  
   public IList<Exception> ExList {get; private set;}

   public bool HasErrors { get { return ExList.Count > 0; } }

   public MyMethod()
   {
       ExList.Clear();
       //- do some logic ---
   }

}

我希望调用MyMethod()函数并检查是否发生了错误,类似于以下代码:

var service = new MyService();

service.MyMethod();

if(service.HasErrors)
{
    // - do some logic
}

service.MyMethod();

if(service.HasErrors)
{
    // - do some logic
}

但是我必须为MyService类中的每个方法手动编写"ExList.Clear();"代码行。 问题是 - 有没有避免这种情况的解决方案?
我需要像下面这样的东西:
public class MyService  
{  
   public IList<Exception> ExList {get; private set;}

   public bool HasErrors { get { return ExList.Count > 0; } }

   private void Precondition()
   {
       ExList.Clear();
   }

   public MyMethod()
   {           
       //- do some logic ---
   }

}

并且 Precondition() 会在每个方法调用时自动调用。


你能不能只是抛出和捕获异常?你会考虑使用它们吗? - alexm
我需要类似于CodeContracts中实现的东西([ContractInvariantMethod] private void ObjectInvariant(){}),但是这只在方法执行后调用。 - Vyacheslav
1
你可以在方法中使用 out List 参数,而不是一个全局的 IList。这样你就可以在方法调用之间维护异常列表。 - Jamie Dixon
@JamieDixon 这让我为方法调用的 out 参数定义 IList。或者在这种情况下,我应该重载每个方法。我需要一些东西,只需编写一次,它就可以适用于此类中的所有未来方法。 - Vyacheslav
1
对我来说,这似乎是一个糟糕的设计,也许考虑定义一个包含IsSuccess和ListExceptions的Result对象,并从您的方法返回它。不知道完整的上下文,仅为异常处理维护状态似乎是不明智的。 - jflood.net
显示剩余2条评论
1个回答

1
另一个你可以考虑的工具是PostSharp。PostSharp是一个AOP框架,允许你定义自定义方面(属性)。
你会对OnMethodBoundaryAspect感兴趣。像下面这样的东西应该能解决问题。args.Instance将是“正在执行方法的实例”。
public class ClearListPrecondition : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        MyService service = args.Instance as MyService;
        if (service == null)
        {
            throw new InvalidOperationException(
              "This aspect can only execute on types of MyService");
        }

        service.ExList.Clear();
        base.OnEntry(args);
    }
}

然后,您可以使用此方面装饰您的服务方法:

[ClearListPrecondition]
public void MyMethod()
{
}

如果您选择为这样一个微不足道的任务采用AOP方法,我强烈建议您重新考虑设计。
首先,应该优先选择抛出异常,但如果您坚持使用AOP,可以从您的方法中返回结果。
例如:
public MethodResult MyMethod()
{
    ....
     if(errorHasOccured)
     {
          return new MethodResult() {Exceptions = exception};
     }
    ....
     return new MethodResult() {ResultOfMethod = ...};
}

public class MethodResult
{
   public IList<Exception> Exceptions {get; set;}
   public bool HasErrors { get { return ExList.Count > 0; } } 
   public string ResultOfMethod {get;set;}

}

您的消费者可以检查方法调用的结果:

var service = new MyService();

var result1 = service.MyMethod();

if(result1.HasErrors)
{
    // - do some logic
}

var result2 = service.MyMethod();

if(result2.HasErrors) 
{
    // - do some logic
}

这将消除重置服务状态的需要,因为它变得无状态(因此线程安全)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接