具有 C# 8 可空引用类型的 TryGetValue 模式

TryGetValue pattern with C# 8 nullable reference types

我正在尝试将一些代码移植到 C# 以启用可为 null 的引用类型,并且我在我们的代码中遇到了一些使用 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
}

我们在这里试图表达的模式是“如果 return 值为真,则 session 为 non-null。如果为假,则不要尝试看看 session,这是垃圾。

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

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

我可以放弃 TryGet 模式并接受可为空的引用类型(这是 Swift 等其他语言似乎在做的事情)例如

Session? GetSession(string key);

或者,我可以使用占位符值来实现我的 "non-null" 承诺,例如

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

还有其他选择吗?

我最初选择了 swift 风格 Session? GetSession() 所以这个答案的原始版本是这么说的。

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

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

如果你像我一样来晚了一点,事实证明 .NET 团队通过一堆参数属性解决了这个问题,比如 System.Diagnostics.CodeAnalysis [=28] 中的 MaybeNullWhen(returnValue: true) =] 可用于 try 模式。

返回一个 swift 风格的可空引用类型效果很好,但是 try 模式可以让你 return 像错误这样的东西作为额外的输出参数。

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"

更多详情: