声明性地添加代码合同(可能与Postsharp?)

时间:2014-03-02 23:19:16

标签: c# code-contracts postsharp

我想在我的代码中为每个具有特定类型参数的方法添加一个Contract.Requires。我怎么做到这一点?

考虑以下简单的例子:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    private string GetValue(int id)
    {
        Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
        return id.ToString();
    }
}

我怎样才能将其更改为:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    [AddContract]
    private string GetValue(int id)
    {
        return id.ToString();
    }
}

然后我可以在其中多播AddContract属性。

我考虑使用PostSharp,但似乎没有用。我认为这可能与PostSharp的IL编织没有很好地处理代码契约创建的元数据有关,但我的知识缺乏该领域。

我的尝试看起来像这样:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    [AddContract]
    private string GetValue(int id)
    {
        return id.ToString();
    }
}

[Serializable]
public class AddContract : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
        args.Proceed();
    }
}

但是没有用 - 静态代码分析无法识别合同。

2 个答案:

答案 0 :(得分:1)

PostSharp的方法是编译时编织,这意味着修改MSIL代码。为了使System.Diagnostics.Contracts能够很好地工作,PostSharp必须在代码合同之后运行。

好消息是您可以使用Code Contracts和PostSharp。 糟糕的是你不能将代码合同与PostSharp一起使用。

在这种情况下,我建议使用装饰模式来解决交叉问题:

  interface IValuesController
  {
    string Get(int id);
  }

  public class ValuesController : IValuesController
  {
    public string Get(int id)
    {
      return id.ToString();
    }
  }

  public class ValuesControllerWithContracts : IValuesController{

    private IValuesController classToDecorate;

    ValuesControllerWithContracts(IValuesController classToDecorate){
      this.classToDecorate = classToDecorate;
    }

    public string Get(int id)
    {
      //decorate get property with contracts
      Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
      return classToDecorate.Get(id);
    }

  }


  //constrution and usage, this work like a charm with Dependecy Inyection container or Factory Patterns
  IValuesController valuesController = new ValuesController();
  IValuesController valuesControllerWithContracts = new ValuesControllerWithContracts(valuesController)
  valuesControllerWithContracts.Get(1);

答案 1 :(得分:0)

AddContract类未定义为属性

[Serializable]
public class AddContractAttribute : MethodInterceptionAspect
{