NotNull和ContractAnnotation("key: null => halt")对R#的影响似乎是相当相似的。我遗漏了什么吗?我应该同时应用两者吗?
发布于 2014-06-02 08:56:36
它们非常相似,但在语义上非常不同。
NotNull指出,预期目标不会为null,但不会声明结果。可能有一个空检查抛出一个ArgumentNullException,或者它可能只是在不检查的情况下使用它,您可以得到一个运行时NullReferenceException。同样,应用程序可能会检查null,记录它并安全地继续。
ContractAnnotation("key: null => halt")告诉ReSharper,如果key参数为null,那么程序流将终止。ReSharper可以这样使用:
string foo = null;
Assert.NotNull(foo); // ContractAnnotation("null => halt")
Assert.Equal(12, foo.length);这个片段中的第二个断言将被标记为死代码,因为ReSharper知道第一个断言在被传递为null时会抛出。
但是,如果Assert.NotNull只是被标记为NotNull属性,那么ReSharper将用警告突出显示foo参数,告诉您不应该传递空值,但是它不知道如果这样做会发生什么。
很微妙,但不一样。如果您要求值永不为空,我将坚持使用NotNull属性,并将ContractAnnotation("null => halt")用于断言样式方法,如果传递null,该方法将明确和显式抛出。
发布于 2014-06-02 13:36:54
简言之:
[NotNull]/[CanBeNull]注释。它们由R#验证,以通知您是否正在违反合同。它们通过接口实现和虚拟方法重写传播。它们很容易理解。[ContractAnnotation]。它不是[NotNull]/[CanBeNull]的替代品。它允许您链接方法输入和输出、链接notnull/null/true/false值、指定将使您的方法为halt的输入。您要传递给[ContractAnnotation]的字符串称为“函数定义表”,这只是对方法主体行为的抽象。在以下情况下,当[ContractAnnotation] / [NotNull]/[CanBeNull]没有足够的表达能力时,通常需要使用[CanBeNull]:
if (!IsNotNullAndAlsoValid(obj)) return; // null => false
Assert.That(x != null); // false => halt
if (!map.TryGetValue(key, out value)) { // => false, value: null
... // + key parameter annotated as [NotNull]
}是的,[NotNull]在语义上不同于[ContractAnnotation("null => halt")]。这很容易在代码中得到说明,有时R#肯定知道执行会因为NRE而停止,并将剩余的代码突出显示为“死”:
C c = null;
c.InstanceMethod(); // possible NRE
c.SomethingElse(); // unreachable code但是当您使用[NotNull]-annotated API时,R#只是提醒您注意“可能的NRE”。这是因为在这种情况下,R#没有足够的信息说明某些值为null,因此不应该将其余的方法突出显示为潜在不可访问的:
C c = AlwaysTrue ? new C() : null;
Util.NotNullAnnotatedMethod(c); // possible NRE
Util.OtherMethod(c); // no warnings here
if (c != null) { ... } // no warnings here虽然[ContractAnnotation]允许您更严格地指定行为,因此R#将更积极地依赖注释:
if (string.IsNullOrEmpty(text)) return; // text: null => false
if (text != null) { ... } // condition always true
else { ... } // unreachable codehttps://stackoverflow.com/questions/23984569
复制相似问题