【问题标题】:Code Contracts in C# 4.0C# 4.0 中的代码协定
【发布时间】:2011-06-09 17:06:39
【问题描述】:

我做了一个这样的方法

class PersonCollection
{
  [Contracts.CanReturnNull]  //dont know if something like this exists?
  IPerson GetPerson(Guid personId)
  {
       if (this.persons.Contains(personId))
            return this.persons[personId];
       else
            return null;
  }
}

现在调用代码需要正确处理空值。有没有办法为所有调用者表达他们需要能够处理此方法返回的空值的合同?

PersonCollection pc = new PersonCollection();
IPerson p = pc.GetPerson(anyId);
p.Name = "Hugo";  // here I want to have a curly line

我想要的是 p 被标记为潜在问题。

编辑 我只是修改了代码并添加了调用代码和预期的行为。我还添加了一个可能在 GetPerson 方法上不存在的属性

【问题讨论】:

  • 在 C# 引用类型变量中,null 作为默认值。除非GetPerson 通过合同确保IPerson 不为空,否则调用者必须处理null 返回的可能性。
  • 我建议将方法名称更改为 GetPersonOrNull,如果您想让调用者清楚他可能会得到一个空值。

标签: c#-4.0 code-contracts design-by-contract


【解决方案1】:

Code Contract 不提供这样的功能,C# 也没有

代码契约只要求调用者在被调用方法的开始遵守某些约束。这些就是所谓的前提条件后置条件是被调用者的职责,定义了被调用方法退出时程序的状态。

契约式设计是定义这些职责的一种方式,而不是告诉调用者他们应该如何处理由被调用方法引起的某些情况。

【讨论】:

  • +1:代码契约让你说“这个参数不能为空”作为前置条件或“这个返回值不会为空”作为后置条件。
【解决方案2】:

默认情况下,您似乎想要的(在阅读 cmets 之后)会发生:

如果在调用代码中开启了代码契约,验证者会认为GetPerson()的返回可以为null。所以:

IPerson GetPerson(Guid personId)
{
   // no pre/post conditions
}

void PrintPerson(IPerson p)
{
   Contract.Requires(p != null);
   ...
}

void Foo()
{
     var p = GetPerson(id);
     PrintPerson(p);    // a warning here: can not verify p != null
}

而且,与问题完全无关,如果 people 是(像)字典,这通常会更有效:

IPerson GetPerson(Guid personId)
{
   Person p = null;

   this.persons.TryGetValue(personId, out p);
   return p;
}

【讨论】:

  • 我只是用我的预期行为扩展了我的问题。实际上,我喜欢用类似属性的方法标记 GetPerson 方法,表示调用者需要能够处理空返回值。
  • @schoet,我明白了,关键是您可以通过 nothing 得到准确的结果。没有 PostCondition 的 GetPerson() 已经在说“我可以返回 null”
  • > 它现在可以工作了,我安装了没有静态检查的版本。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多