Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning Null Value for Unknown Type

I'm trying to write the following method using generics. (My actual method is more complex than this.)

public T ParseDictionaryItem<T>(string s, Dictionary<string, T> dictionary)
{
    T result;
    if (dictionary.TryGetValue(s, out result))
        return result;
    // TODO: Return special value such as null to indicate invalid item
}

My goal is to return something like null if the item is not in the dictionary.

The problem is that I don't know what type T is. If T was an integer, for example, then I should return the type T?. However, if T is a class, then it is already nullable. And I won't know this until run time.

Can anyone see a clean way to return a special value in this method to indicate the item is invalid? I'm open to returning something other than null, but it has to be a special value. (0 is not a special value for integers.)

like image 334
Jonathan Wood Avatar asked May 14 '15 14:05

Jonathan Wood


2 Answers

I would suggest returning a ParseResult<T>, which is defined as something like:

public struct ParseResult<T>
{
    // Or an exception, or a way of creating an exception
    private readonly bool success;
    private readonly T value;

    // Accessors etc
}

That way you don't have to worry about nullability, and you can make it very clear what you're doing. This is the pattern I've used in Noda Time and to my mind it's worked very well. (Currently we use a class rather than a struct, but I might change that...)

I prefer it to other approaches because:

  • It is clean to call, unlike using an out parameter
  • It doesn't need ugly and potentially expensive try/catch handling
  • It behaves exactly the same way whether T is a reference type or a value type
  • It's flexible enough to represent the situation where null is a successful parse value
  • You can still propagate the cause of a failure without throwing the exception when you don't need to
like image 57
Jon Skeet Avatar answered Sep 19 '22 18:09

Jon Skeet


Perhaps two overloads would help:

public T? ParseStructDictionaryItem<T>(string s, Dictionary<string, T> dictionary) where T : struct
{
    T result;
    if (dictionary.TryGetValue(s, out result))
        return result;
    return null;
}

public T ParseReferenceDictionaryItem<T>(string s, Dictionary<string, T> dictionary) where T : class
{
    T result;
    if (dictionary.TryGetValue(s, out result))
        return result;
    return default(T);
}
like image 38
Yuval Itzchakov Avatar answered Sep 20 '22 18:09

Yuval Itzchakov