【问题标题】:Why does null-forgiving operator (!) does not work for parameter?为什么容错运算符(!)不适用于参数?
【发布时间】:2021-12-10 13:42:22
【问题描述】:

考虑以下 xUnit 测试(这是我遇到的最流行和最烦人的案例):

public class UnitTest1
{

    [Fact]
    public async Task Test1()
    {
        var result = await this.FindAsync();

        Assert.NotNull(result); // Line 1
        Assert.Equal(3, result.Length); // Line 2: Null warning here
        Assert.Equal("yes", result.ToLower()); // Line 3
    }

    // I use async to demonstrate a shortcoming of workaround
    async Task<string?> FindAsync()
    {
        return await Task.FromResult("Yes");
    }

}

由于 xUnit 还没有 [NotNull] 注释,编译器不知道 result 从那里开始不能是 null。但是,如果我在第 1 行将其标记为“not null”,则它不起作用:

        Assert.NotNull(result!); // Tooltip says "result" is not null here
        Assert.Equal(3, result.Length); // But here it says "result" may be null

这些解决方法有效,但有缺点:

// Mark as not null at the assignment:
// - Has to add parentheses in many cases
// - Does not work if it may actually be null
var result = (await this.FindAsync())!;

// Mark on the first usage, like at line 2:
// This has to be at the first line.
// If you move code around or remove it, you get the warning back and have to move the ! around
Assert.Equal(3, result!.Length);

如果我将! 放在第 1 行 Assert.NotNull(result!);,为什么它不能“正常”工作?这是编译器错误吗?

【问题讨论】:

  • 第 1 行没有警告,所以 ! 没有什么可以抑制的,所以它没有效果
  • @canton7 虽然您可能是对的,但这使得操作员如此违反直觉。当我使用! 时,我希望编译器知道从那里开始,它不为空,而不仅仅是“不要在此处发送警告”
  • 这不是它的作用。它用于代码中的特定点以抑制该点的可为空警告。这不是一个注释,意思是“这个对象不能在这里为空”,它的意思是“闭嘴关于这里生成的这个特定警告”
  • @LukeVo:文档正在讨论您放置! 的特定表达式。它没有说明“以及今后的所有表达方式”。
  • 第 3 行没有警告,因为编译器知道,如果 result 是 null,第 2 行会抛出 NullReferenceException 导致第 3 行无法访问

标签: c# .net null roslyn nullable-reference-types


【解决方案1】:

关于 xUnit,较新版本的 xUnit 确实支持空注释。例如,版本2.4.2-pre.13。这目前处于预发布阶段,但根​​据我的经验,它运行良好。

关于在第一次抑制后看到警告,这取决于被抑制的内容。

这不会发出警告:

object? o = null;
o!.ToString();
o.ToString(); // no warning

这确实会发出警告:

object? o = null;
object j = o!;
o.ToString(); // warning

人们可以合理地争辩说第二种情况不应该发出警告。也许在https://github.com/dotnet/roslyn 上打开一个问题来询问这个问题。看起来它确实可以改善使用可为空引用类型的体验。

【讨论】:

  • 谢谢,我submitted one 他们认为这是他们的设计决定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 2014-10-10
  • 2019-05-22
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
相关资源
最近更新 更多