Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement generic collection lookup method that can return class or nullable struct?

Tags:

c#

generics

I want a typed lookup helper function for a heterogenous collection: It should return a struct or class, else null if the item is not found. Below is an example using a trivial collection lookup, but it could be a database call or whatever.

Is there any way to achieve this with a single method signature?

    public T GetClass<T>(string key)  where T : class
    {
        object o;
        if (Contents.TryGetValue(key, out o))
        {
            return o as T;
        }
        return null;
    }

    public T? GetStruct<T>(string key) where T : struct
    {
        object o;
        if (Contents.TryGetValue(key, out o))
        {
            if (o is T)
            {
                return (T?) o;
            }
        }
        return null;
    }

What I've already tried:

  • I understand that generic restrictions can't be used to disambiguate overloads. So I can't simply give these two methods the same name.
  • Returning (Default) T isn't an option, since 0 is a valid int value.
  • I have tried calling with <int ?> as the type, but as discussed, Nullable<T> isn't a reference type.

Is there some way to indicate that I'm going to return a boxed int?

like image 674
Steve Weil Avatar asked May 02 '12 19:05

Steve Weil


2 Answers

Is there any way to achieve this with a single method signature?

There's a horrible (truly hideous) way to do it using optional parameters so that the calling code can look the same in both cases. It's icky though.

Options:

  • Return a Tuple<T, bool> instead of using nullity
  • Use an out parameter (like int.TryParse etc)
  • Use different method names

Note that by signalling the absence of a value separately, you can make null a valid "found" result, which can be useful sometimes. Or you may want to just guarantee that it'll never be returned.

If you really want to use nullity, I'd go for the last option. I believe it will make your code clearer anyway. IMO, overloading should really only be used when the methods do exactly the same thing expressed using different parameters - whereas returning Nullable<T> as the return type in one case and T as the return type in the other case can't really be seen that way.

like image 104
Jon Skeet Avatar answered Nov 03 '22 23:11

Jon Skeet


The following method works for both classes and nullable structures:

public static T GetValue<T>(string key)
{
    object o;
    if (Contents.TryGetValue(key, out o))
    {
        if (o is T)
        {
            return (T)o;
        }
    }
    return default(T);
}

Usage:

int?   result1 = GetValue<int?>("someInt");
string result2 = GetValue<string>("someString");

Notice how the ? is part of generic type argument and not defined by the method on the return type.

like image 33
dtb Avatar answered Nov 04 '22 00:11

dtb