Moddaman
Moddaman

Reputation: 2808

Generic throw function for non-nullable types

I am trying to convert an existing project to using nullable reference types properties using non-nullable properties during initialization.

I am using this approach for getting properties which should exist:

public class Dog
{
    private Person? _person;
    public int Id { get; set; }

    public string Name { get; set; }

    public Person Person
    {
        get => _person ?? throw new InvalidOperationException(
            $"Unset property {nameof(_person)}. You probably forgot to Include it");
        set => _person = value;
    }
}

But it's tedious to write this for almost every property, so I've tried to make a generic ThrowOrGet() function:

public static class Util
{
    public static T ThrowOrGet<T>([AllowNull] T obj)
    {
        if (obj == null)
        {
            throw new InvalidOperationException(
                $"Unset property {nameof(obj)}. You probably forgot to Include it");
        }
        return obj;
    }
}

Which is used like this:

public class Dog
{
    private Person? _person;
    public int Id { get; set; }

    public string Name { get; set; }

    public Person Person
    {
        get =>  Util.ThrowOrGet(_person); ---> "Possible null reference return"
        set => _person = value;
    }
}

But the the function Util.ThrowOrGet(_person); now says that it's a possible null reference return. If I inline the function, it works as intended. Is there a way to make a generic function that does this?

Upvotes: 0

Views: 131

Answers (1)

yaakov
yaakov

Reputation: 5850

If you're only going to use ThrowOrGet on reference types (which you should, as it doesn't make sense for value types), then you should declare it like this:

public static T ThrowOrGet<T>(T? obj) where T : class
{
    if (obj == null)
    {
        throw new InvalidOperationException(
            $"Unset property {nameof(obj)}. You probably forgot to Include it");
    }
    return obj;
}

This says that the function accepts a nullable argument, and always returns a non-nullable reference. It's better to follow this pattern than rely on the attributes, as they're really just there for complex cases, which this is not.

Upvotes: 4

Related Questions