【问题标题】:TryGetValue pattern with C# 8 nullable reference types具有 C# 8 可空引用类型的 TryGetValue 模式
【发布时间】:2019-04-04 22:58:40
【问题描述】:

我正在尝试将一些代码移植到 C# 以启用可为空的引用类型,并且我在代码中遇到了一些使用 TryGetValue 模式的函数。

也就是说,是这样的:

public bool TryGetSession(string key, out Session session) {
    session = null; // assign default
    // code which looks for a session based on the key, etc
    // return true or false if we found the session key
}

我们在这里试图表达的模式是“如果返回值为真,那么session 是非空的。如果为假,那么甚至不要尝试查看会话,这是垃圾。

问题是我现在在 session = null 上收到警告,但我不得不将 something 放在那里,因为 out 参数必须由函数填充。

这里有好的答案吗?我的想法:

我可以放弃 TryGet 模式并采用可为空的引用类型(这是 Swift 等其他语言似乎所做的),例如

Session? GetSession(string key);

或者,我可以使用占位符值来兑现我的“非空”承诺,例如

public bool TryGetSession(string key, out Session session) {
    session = new InvalidSession(); // assign default
    ...
}

还有其他选择吗?

【问题讨论】:

  • public bool TryGetSession(string key, out Session? session) 不是表达这一点的合适方式吗?如果输出参数必须为非空,则“TryGet”实际上没有意义。
  • AFAIK,这是 !-operator 需要忽略警告的情况之一。我实际上设计了我的方法,比如bool TryGetValue(TKey key, TValue? value) (因为他们就是这样做的),当然,在检查返回的布尔值之后,在调用代码中使用了value!。希望有更智能的东西!
  • @madreflection out Session? 将是在 C# 类型系统中表达它的最佳方式,但是之后我必须显式地检查该值,或者使用 ! - 这两者不用做就好了
  • 相当不幸。我知道这仍然是一个额外的步骤,但模式匹配对于 null 检查似乎相对惯用,并且可以内联完成:if (TryGetSession(key, out Session? temp) && temp is Session session).

标签: c# nullable


【解决方案1】:

如果你像我一样迟到了,事实证明 .NET 团队通过System.Diagnostics.CodeAnalysis 空间中的MaybeNullWhen(returnValue: true) 等一系列参数属性解决了这个问题,你可以将其用于尝试模式.

返回 swift 样式的可为空引用类型效果很好,但 try 模式允许您将错误之类的内容作为附加输出参数返回。

public bool TryGetSession(string key, [NotNullWhen(returnValue: true)] out Session? session, [NotNullWhen(returnValue: false)] out string? error)
{
  // etc
}


// This is okay:
if(TryGetSession("cheese", out var session, out var error))
{
  var time = session.Time;
}

// But this is not:
_ = TryGetSession("cheese", out var session, out var error);
var time = session.Time;
// "CS8602: Dereference of a potentially null reference"

更多细节:

【讨论】:

  • 看起来它仅适用于 .NET Core,尽管您可以在 .NET 4.8 中使用此 C#8 语言功能(官方仅部分支持)
【解决方案2】:

我最初最终选择了 swift-style Session? GetSession() 所以这个答案的原始版本是这样说的。

我后来根据 Nick Darvey 的回答改用 [NotNullWhen(returnValue: true)]。由于 C# 具有 out var 特性(并且因为 C# 缺少 'if let'),TryGet 模式最终更加简洁且更适合。

注意:这些属性仅存在于 .NET Core 3.0 或更高版本中,它们不在桌面 .NET 框架中,但是您可以自己定义它们并将它们应用到您自己的方法中,它们会按预期工作。

【讨论】:

猜你喜欢
  • 2018-07-18
  • 1970-01-01
  • 1970-01-01
  • 2020-03-23
  • 1970-01-01
  • 2019-07-02
  • 2020-08-08
相关资源
最近更新 更多