Programmatic equivalent of default(Type)

前端 未结 14 1496
时光取名叫无心
时光取名叫无心 2020-11-22 05:28

I\'m using reflection to loop through a Type\'s properties and set certain types to their default. Now, I could do a switch on the type and set the defau

相关标签:
14条回答
  • 2020-11-22 06:24
     /// <summary>
        /// returns the default value of a specified type
        /// </summary>
        /// <param name="type"></param>
        public static object GetDefault(this Type type)
        {
            return type.IsValueType ? (!type.IsGenericType ? Activator.CreateInstance(type) : type.GenericTypeArguments[0].GetDefault() ) : null;
        }
    
    0 讨论(0)
  • 2020-11-22 06:25

    Why not call the method that returns default(T) with reflection ? You can use GetDefault of any type with:

        public object GetDefault(Type t)
        {
            return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
        }
    
        public T GetDefaultGeneric<T>()
        {
            return default(T);
        }
    
    0 讨论(0)
  • 2020-11-22 06:25

    If you're using .NET 4.0 or above and you want a programmatic version that isn't a codification of rules defined outside of code, you can create an Expression, compile and run it on-the-fly.

    The following extension method will take a Type and get the value returned from default(T) through the Default method on the Expression class:

    public static T GetDefaultValue<T>()
    {
        // We want an Func<T> which returns the default.
        // Create that expression here.
        Expression<Func<T>> e = Expression.Lambda<Func<T>>(
            // The default value, always get what the *code* tells us.
            Expression.Default(typeof(T))
        );
    
        // Compile and return the value.
        return e.Compile()();
    }
    
    public static object GetDefaultValue(this Type type)
    {
        // Validate parameters.
        if (type == null) throw new ArgumentNullException("type");
    
        // We want an Func<object> which returns the default.
        // Create that expression here.
        Expression<Func<object>> e = Expression.Lambda<Func<object>>(
            // Have to convert to object.
            Expression.Convert(
                // The default value, always get what the *code* tells us.
                Expression.Default(type), typeof(object)
            )
        );
    
        // Compile and return the value.
        return e.Compile()();
    }
    

    You should also cache the above value based on the Type, but be aware if you're calling this for a large number of Type instances, and don't use it constantly, the memory consumed by the cache might outweigh the benefits.

    0 讨论(0)
  • 2020-11-22 06:25

    Can't find anything simple and elegant just yet, but I have one idea: If you know the type of the property you wish to set, you can write your own default(T). There are two cases - T is a value type, and T is a reference type. You can see this by checking T.IsValueType. If T is a reference type, then you can simply set it to null. If T is a value type, then it will have a default parameterless constructor that you can call to get a "blank" value.

    0 讨论(0)
  • 2020-11-22 06:26

    The Expressions can help here:

        private static Dictionary<Type, Delegate> lambdasMap = new Dictionary<Type, Delegate>();
    
        private object GetTypedNull(Type type)
        {
            Delegate func;
            if (!lambdasMap.TryGetValue(type, out func))
            {
                var body = Expression.Default(type);
                var lambda = Expression.Lambda(body);
                func = lambda.Compile();
                lambdasMap[type] = func;
            }
            return func.DynamicInvoke();
        }
    

    I did not test this snippet, but i think it should produce "typed" nulls for reference types..

    0 讨论(0)
  • 2020-11-22 06:30
    • In case of a value type use Activator.CreateInstance and it should work fine.
    • When using reference type just return null
    public static object GetDefault(Type type)
    {
       if(type.IsValueType)
       {
          return Activator.CreateInstance(type);
       }
       return null;
    }
    

    In the newer version of .net such as .net standard, type.IsValueType needs to be written as type.GetTypeInfo().IsValueType

    0 讨论(0)
提交回复
热议问题