简体   繁体   中英

TryGetValue pattern with C# 8 nullable reference types

I'm playing with porting some code to C# to enable nullable reference types, and I've encountered some functions in our code that use the TryGetValue pattern.

That is, something like this:

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
}

The pattern which we're trying to express here is "if the return value is true, then session is non-null. If false, then don't even attempt to look at the session, it's garbage.

The problem is I now get a warning on session = null , but I'm forced to put something there as out parameters MUST be populated by the function.

Is there a good answer here? My thoughts:

I could drop the TryGet pattern and embrace the nullable reference types (This is what other languages like Swift seem to do) eg

Session? GetSession(string key);

Or, I could live up to my "non-null" promise using a placeholder value eg

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

Are there any other options?

If you're arriving at this a little late, like me, it turns out the .NET team addressed it through a bunch of parameter attributes like MaybeNullWhen(returnValue: true) in the System.Diagnostics.CodeAnalysis space which you can use for the try pattern.

Returning a swift-style nullable reference type works well, but the try pattern lets you return things like errors as additional out parameters.

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"

Further details:

I originally ended up going with the swift-style Session? GetSession() Session? GetSession() so the original version of this answer said that.

I later switched to using [NotNullWhen(returnValue: true)] as per Nick Darvey's answer. Because of the out var feature that C# has (and because C# lacks 'if let'), the TryGet pattern ends up being more concise and a better fit.

Note: These attributes only exist in .NET Core 3.0 or greater, they're not in the desktop .NET framework, however you can define them yourself and apply them to your own methods and they work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM