【问题标题】:Is there any "forgiven null-forgiving operator" warning facility?是否有任何“宽恕的零宽恕操作员”警告设施?
【发布时间】:2020-12-29 08:14:19
【问题描述】:

考虑一下这个不太安全的 sn-p:

private object? _obj;

private void Dummy()
{
    if (this._obj == null)
    {
        this.Create();
    }
    Console.WriteLine(this._obj!.ToString());  //note the null-forgiving operator
}

private void Create()
{
    this._obj = new object();
}

虽然_obj字段明确保证不为空,但检查器无法理解。清除警告的解决方案是添加 null-forgiving 运算符,尽管我希望避免或谨慎使用它。

修改后的 sn-p 导致了更安全的模式和完全可检查的代码:

private void BetterDummy()
{
    this._obj ??= this.BetterCreate();
    Console.WriteLine(this._obj!.ToString());
}

private object BetterCreate()
{
    return new object();
}

但是,我可能忘记从它所在的位置删除!(假设有很多这样的地方)。该操作员禁止对该点进行检查,因此我想将代码设置为最佳。

我想知道是否有一个选项可以突出显示/警告“不再有用”的 null-forgiving 运算符,以便快速找到它们并将其从代码中删除。

【问题讨论】:

  • 由于_obj 是一个字段而不是本地属性,如何保证另一个线程不会使您保证的null 分配和Console.WriteLine 之间的字段为空?
  • @Knoop 你是对的。我的原始代码是真正安全的,因为有一个信号量锁定它。但是,我的意思是对第一个 sn-p 的“更安全”。
  • “真正安全”很遗憾,这不是真的。 semaphore 只有在每个人都玩得很好的情况下才有效。即使您通过属性等强制它,人们仍然可以作弊并通过反射访问private 支持字段。保证是一件非常复杂的事情,您似乎发现了一个编译器似乎有点困惑的场景(不会警告删除它,但如果它被删除也不会警告添加它),但 imo 正确的方法不会是告诉你删除它,因为在这种情况下没有完全的保证,即使使用信号量也是如此。
  • @Knoop 不关注并发或类似问题:静态检查不考虑这一点。我说的是那个,而不是线程安全:上面只是一个例子,但它可能完全不同。
  • 我知道 Resharper 会在不需要的地方突出显示操作符的用法。并且可以进行重构以删除不需要的部分。

标签: c# nullable static-analysis


【解决方案1】:

虽然_obj字段明确保证不为空

但事实并非如此。正如@Knoop 指出的那样,不能保证在从对Create 的调用返回及其评估之间,其他线程不会影响您的对象。

我建议的第一件事是让您的字段不可为空。我看不到任何其他方法,但您提供的方法明确暗示该值不应为空。

如果您不想允许可能不安全的!.,为什么不使用更安全的?.

private void EvenBetterDummy()
{
    this._obj ??= this.BetterCreate();
    Console.WriteLine(this._obj?.ToString());
}

或者,如果您有默认值:

private void EvenBetterDummy()
{
    this._obj ??= this.BetterCreate();
    Console.WriteLine(this._obj?.ToString() ?? "oops, that one 's a null");
}

【讨论】:

  • 这是使用可空标志(否则object?_obj 字段没有意义。所以BetterCreate 实际上保证不会返回null
  • 这段代码没问题,但没有回答我的问题。不要考虑实际的可空性,而是专注于找到可容空运算符的方法。
  • @MarioVernari 我想我不太明白你的问题。能否请您对其进行编辑以使其更清楚您所关注的具体内容?您是否正在寻找一种方法来查找“!。”,删除它不会导致警告?
  • 我认为@Knoop 的评论已经足够了。静态检查不考虑并发性,但让我们想象一下它会这样做,我想对此有所提示。现在,with null-forgiving,我会有一个“一切正常”,但 没有 analisys 会提醒该字段“可能为空”。我要这个!所以,我想找到导致危险代码的 null-forgiving 运算符,然后删除它们(当然,如果可能的话)。
  • @MarioVernari 我认为当@Knoop 提到线程安全时你可能会漏掉一点。编译器和代码分析工具不能保证可空对象不为空,除了对整个代码库进行完整检查,这对于编译器/ca 工具来说任务太广泛了,需要立即重新检查在您更改任何内容的那一刻,任何地方的整个解决方案。确保不需要!. 的唯一方法是使您的对象不可为空,因此编译器知道不允许将其设置为空。
猜你喜欢
  • 1970-01-01
  • 2012-08-29
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
  • 2019-09-02
相关资源
最近更新 更多