C# 4.0中的代码合约

4
我写了一个类似这样的方法:
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,否则调用者必须处理可能返回null的情况。 - Peter K.
我建议将你的方法名称更改为GetPersonOrNull,如果你想向调用者清楚表明他可能会得到一个空值。 - koenmetsu
2个回答

2

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

Code Contracts只要求调用者在调用方法开始时遵守某些约束条件。这些被称为前置条件后置条件是被调用者的责任,并定义了程序状态在调用方法退出时会是什么样子。

设计按合同实现是一种定义这些责任的方式,而不是告诉调用者如何处理由调用方法引起的某些条件。


2
+1:代码合同允许您将“此参数不能为空”作为前置条件或将“此返回值不会为空”作为后置条件。 - Peter K.

1

根据评论所述,您似乎想要的是默认行为:

如果在调用代码中启用了代码合同,则验证器将认为GetPerson()的返回值可能为空。因此:

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
}

而且,与问题完全无关,如果persons是(类似于)字典,这通常会更有效率:

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

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

我刚刚扩展了我的问题,并附上了我的期望行为。实际上,我想用类似属性的东西来标记GetPerson方法,表示调用者需要能够处理空返回值。 - schoetbi
@schoet,我明白了,关键是你什么都不做就能得到那个结果。没有后置条件的GetPerson()已经在说“我可能会返回null”。 - H H
现在它正在工作,我安装了没有静态检查的版本。谢谢! - schoetbi

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