1

I have list that that either will be null or has a single list value.

I want to be able to convert this list to return default value according to the calling function as per below. Can someone help in figuring out how to define GetValue()?

var xx = new List<int>{1};
var yy = new List<int?>{};
var zz = new List<int?>{1};

Getvalue<int>(xx);//return 1
Getvalue<long>(xx);//return 1
Getvalue<int?>(xx);//return 1
Getvalue<long?>(xx);//return 1

Getvalue<int>(yy);//return 0
Getvalue<long>(yy);//return 0
Getvalue<int?>(yy);//return null
Getvalue<long?>(yy);//return null

Getvalue<int>(zz);//return 1
Getvalue<long>(zz);//return 1
Getvalue<int?>(zz);//return 1
Getvalue<long?>(zz);//return 1

I have below function, but it only work for normal type like integer, long, but I need something that work with List instead now...

public T GetValue<T>(object value)
{
    if (value == null || value == DBNull.Value)
    {
        return default(T);
    }
    else
    {
        //return (T)value;
        return (T)Convert.ChangeType(value, typeof(T));
    }
}

Most efficient way to check for DBNull and then assign to a variable?

Community
  • 1
  • 1
user3663854
  • 463
  • 2
  • 8
  • 21

2 Answers2

1

Does the following do what you want?

public static T GetValue<T>(object value)
{
    if (value == null || value == DBNull.Value)
    {
        return default(T);
    }
    else if (value.GetType().IsGenericType
          && value.GetType().GetGenericTypeDefinition().Equals(typeof(List<>)))
    {
        var list = ((System.Collections.IList)value).Cast<object>();

        if (!list.Any())
            return default(T);

        return GetValue<T>(list.Single());
    }
    else
    {
        var type = typeof(T);

        if (type.IsGenericType
         && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {                   
            if (value == null) 
                return default(T); 

            type = Nullable.GetUnderlyingType(type);
        }           

        return (T)Convert.ChangeType(value, type);
    }
}

Basically you just have to check for lists first and handle them recursively.

I also had to add behaviour to handle Nullable<T> types.

Here is a working example generating the following output for your examples (blank lines represent null):

1
1
1
1
0
0


1
1
1
1
Good Night Nerd Pride
  • 8,245
  • 4
  • 49
  • 65
1

It is possible to write a single GetValue method that will do it all for any list, but I recommend against it because it involves a bunch of icky runtime conversions:

public T GetValue<T>(IEnumerable values) {
    if (values == null) return default(T);
    IEnumerator e = values.GetEnumerator();
    if (!e.MoveNext()) return default(T);
    if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>)) {
        return (T) Convert.ChangeType(e.Current, Nullable.GetUnderlyingType(typeof(T)));
    } else {
        return (T) Convert.ChangeType(e.Current, typeof(T));
    }
}

This can be changed to accept an object instead so it can almost literally convert anything, but I'm not doing that because it involves even more icky runtime conversions.

Instead, don't try to do too much in one function and introduce one that will unwrap a single-element list instead, as an extension method:

public static class ListExtensions {
    public static T Unwrap<T>(this List<T> values) {
        if (values == null || values.Count == 0) return default(T);
        return values[0];
    }
}

And do the conversion outside, like so:

(int) xx.Unwrap()

Which has the benefit of allowing the compiler to check if what you're doing is sensible. This does assume you have strongly-typed lists, as your question seems to imply.

Jeroen Mostert
  • 27,176
  • 2
  • 52
  • 85