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) e.g.
Session? GetSession(string key);
Or, I could live up to my "non-null" promise using a placeholder value e.g.
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()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With