default(T) with empty collection instead of null

前端 未结 2 557
盖世英雄少女心
盖世英雄少女心 2020-12-14 11:27

I\'d like to have generic method which returns default value for passed type, but for collection type I\'d like to get empty collection instead of null, for example:

2条回答
  •  感动是毒
    2020-12-14 11:57

    You can use the magic of a static constructor to do this efficiently. To use the default value in code, simply use Default.Value. The value will only be evaluated for any given type T once for the duration of your application.

    public static class Default
    {
        private static readonly T _value;
    
        static Default()
        {
            if (typeof(T).IsArray)
            {
                if (typeof(T).GetArrayRank() > 1)
                    _value = (T)(object)Array.CreateInstance(typeof(T).GetElementType(), new int[typeof(T).GetArrayRank()]);
                else
                    _value = (T)(object)Array.CreateInstance(typeof(T).GetElementType(), 0);
                return;
            }
    
            if (typeof(T) == typeof(string))
            {
                // string is IEnumerable, but don't want to treat it like a collection
                _value = default(T);
                return;
            }
    
            if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
            {
                // check if an empty array is an instance of T
                if (typeof(T).IsAssignableFrom(typeof(object[])))
                {
                    _value = (T)(object)new object[0];
                    return;
                }
    
                if (typeof(T).IsGenericType && typeof(T).GetGenericArguments().Length == 1)
                {
                    Type elementType = typeof(T).GetGenericArguments()[0];
                    if (typeof(T).IsAssignableFrom(elementType.MakeArrayType()))
                    {
                        _value = (T)(object)Array.CreateInstance(elementType, 0);
                        return;
                    }
                }
    
                throw new NotImplementedException("No default value is implemented for type " + typeof(T).FullName);
            }
    
            _value = default(T);
        }
    
        public static T Value
        {
            get
            {
                return _value;
            }
        }
    }
    

提交回复
热议问题