微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在某些但不是所有参数情况下,意外需要断言 Collection?.Method(...)

如何解决在某些但不是所有参数情况下,意外需要断言 Collection?.Method(...)

注意。问题不是关于空引用保护运算符 (X?.Y) 的含义。我知道标题有点神秘,但我还没有想出更好的方法来表达它。对不起。

我正在使用 FindOneAndReplaceAsync(...),根据它,选项的认值为 null

  await Things.FindOneAndReplaceAsync(
    x => x.Id == target.Id,replacement,null,token);

传递一个明确的 null 就像预期的那样工作。但是,当我创建 FindOneAndReplaceOptions 的实例时,编译器突然担心我正在执行搜索的对象未定义。

FindOneAndReplaceOptions<Thing> options = new FindOneAndReplaceOptions<Thing>();
await Things.FindOneAndReplaceAsync(
  x => x.Id == target.Id,options,token);

为了编译,我必须断言 Things 为非空。

FindOneAndReplaceOptions<Thing> options = new FindOneAndReplaceOptions<Thing>();
await Things?.FindOneAndReplaceAsync(
  x => x.Id == target.Id,token);

虽然我理解这个建议,但我无法理解为什么只有在传递 options 对象的实例时才会出现投诉。我检查过我没有因超载而绊倒。即使没有实际的实例通过,也会出现同样的现象,就像这样。

FindOneAndReplaceOptions<Thing> options = null;
await Things?.FindOneAndReplaceAsync(
  x => x.Id == target.Id,token);

这是怎么回事?感觉很迷茫...

解决方法

这很有趣。如果你把它缩减到最小的复制器,你会得到这个:

#nullable enable

public class C
{
    public void M(IMongoCollection<string>? collection)
    {
        // No warning
        collection.FindOneAndReplaceAsync(null);
    }
    
    public void N(IMongoCollection<string>? collection)
    {
        // Warning
        collection.FindOneAndReplaceAsync(new FindOneAndReplaceOptions<string>());
    }
}

#nullable disable

public interface IMongoCollection<TDocument>
{
    Task FindOneAndReplaceAsync<TProjection>(FindOneAndReplaceOptions<TDocument,TProjection> options = null);
}

public static class MongoCollectionExtensions
{
    public static Task FindOneAndReplaceAsync<TDocument>(
        this IMongoCollection<TDocument> doc,FindOneAndReplaceOptions<TDocument,TDocument> options = null) => Task.CompletedTask;
}

public class FindOneAndReplaceOptions<TDocument,TProjection>
{
}

public class FindOneAndReplaceOptions<TDocument> : FindOneAndReplaceOptions<TDocument,TDocument>
{
}

SharpLab 上查看。

这实际上归结为三件事:

  1. 重载解决方案更喜欢实例方法而不是扩展方法。
  2. 您可以在 null 接收器上调用扩展方法,但不能调用实例方法。
  3. MongoDB 没有可空性注释

请注意,IMongoCollection<TDocument>.FindOneAndReplaceAsync<TProjection>(...)this MongoDB method 的简化版本)的签名具有 TProjection 类型参数,该参数链接到 FindOneAndReplaceOptions<TDocument,TProjection> 参数。

如果将 null 作为 options 的值传入,编译器无法推断 TProjection 类型参数是什么,因此重载解析失败,并移至扩展方法。

那个 FindOneAndReplaceAsync 扩展方法(它是 this MongoDB method 的简化版本)没有 TProjection 类型参数,它的 options 参数类型为 {{1 }}).

这意味着编译器拥有推断所有类型参数所需的所有信息,即使您将 FindOneAndReplaceOptions<TDocument,TDocument> 作为 null 的值传入。

因此,当您调用 options 时,编译器无法绑定到实例方法(因为它无法推断 collection.FindOneAndReplaceAsync(null)),而必须绑定到扩展方法。

由于 MongoDB 没有可空性注释,编译器根本不知道 TProjection 参数的 null 值是否被允许,因此它假定它是允许的。因此,没有可空性警告。

然而,当你传入一个 doc 的实例(它继承自 FindOneAndReplaceOptions<TDocument> 时,编译器有足够的信息来推断 FindOneAndReplaceOptions<TDocument,TDocument> 的类型:它与 {{1 }}!所以它现在可以绑定到实例方法,并在可能是 TProjection 的东西上调用实例方法值得警告。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?