fharreau
fharreau

Reputation: 2347

How to correctly write a `bool TrySomething(out)` implementation for both reference and value types?

Considering the following class:

public class Property
{
    public string StringValue { get; private set; }

    private Property(string value)
    {
        this.StringValue = value;
    }
}

I am trying to write a TrySomething method (with nullable enabled). I first wrote something like that:

public bool TryGetValue<T>([NotNullWhen(true)] out T? value)
{
    value = JsonSerializer.Deserialize<T>(this.StringValue);

    return value != null;
}

When using such implementation with reference type, I get the CS8602 warning when writing the following code:

if (property.TryGetValue<Foo>(out var v))
{
    v.ToString(); // OK
}
else
{
    v.ToString(); // CS8602
}

But when writing it with value types, it does not:

if (property.TryGetValue<int>(out var v))
{
    v.ToString(); // OK
}
else
{
    v.ToString(); // OK
}

Is it possible to write such methods for value types?

Upvotes: 1

Views: 78

Answers (1)

Guru Stron
Guru Stron

Reputation: 143098

You need to provide "correct" type for your generic (and use Value instead ToString() to test the warning):

var property = ...;

if (!property.TryGetValue<int?>(out var i))
{
    var value = i.Value; // warning CS8629: Nullable value type may be null.
}

Demo @sharplab.io

Or constrain the generic parameter to value types:

public class Property
{   
    public bool TryGetValueType<T>([NotNullWhen(true)] out T? value) where T: struct
    {
        //...
    }
}

Demo @sharplab.io

The problem is indeed in using value types - for them T and T? for unconstrained generic types are treated as the same type (i.e. for you original implementation/call TryGetValue<int> T and T? both are int, so i.Value will not even compile) - see more in the answer for Nullability and generics in .NET 6

Upvotes: 1

Related Questions