首页 文章

程序化等效的默认值(类型)

提问于
浏览
468

我正在使用反射来遍历 Type 的属性并将某些类型设置为默认值 . 现在,我可以对类型进行切换并明确设置 default(Type) ,但我宁愿在一行中进行 . 有默认的程序化等价物吗?

13 回答

  • 5

    为什么不用反射调用返回默认值(T)的方法?您可以使用任何类型的GetDefault:

    public object GetDefault(Type t)
        {
            return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
        }
    
        public T GetDefaultGeneric<T>()
        {
            return default(T);
        }
    
  • 37

    你可以使用 PropertyInfo.SetValue(obj, null) . 如果调用值类型,它将为您提供默认值 . 记录此行为in .NET 4.0in .NET 4.5 .

  • 0
    • 如果是值类型,请使用Activator.CreateInstance,它应该可以正常工作 .

    • 使用引用类型时,只返回null

    public static object GetDefault(Type type)
    {
       if(type.IsValueType)
       {
          return Activator.CreateInstance(type);
       }
       return null;
    }
    

    在较新版本的.net中,例如.net标准, type.IsValueType 需要写成 type.GetTypeInfo().IsValueType

  • 7

    如果您对代码之外定义的规则进行编码,则可以创建Expression,即时编译并运行它 .

    以下扩展方法将采用Type并通过 Expression 类上的Default method获取从default(T)返回的值:

    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()();
    }
    

    您还应该根据 Type 缓存上述值,但要注意,如果您为大量 Type 实例调用此值,并且不要经常使用它,则缓存所消耗的内存可能会超过收益 .

  • 3

    为什么你说仿制药不合适?

    public static object GetDefault(Type t)
        {
            Func<object> f = GetDefault<object>;
            return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null);
        }
    
        private static T GetDefault<T>()
        {
            return default(T);
        }
    
  • 3

    这是优化Flem的解决方案:

    using System.Collections.Concurrent;
    
    namespace System
    {
        public static class TypeExtension
        {
            //a thread-safe way to hold default instances created at run-time
            private static ConcurrentDictionary<Type, object> typeDefaults =
               new ConcurrentDictionary<Type, object>();
    
            public static object GetDefaultValue(this Type type)
            {
                return type.IsValueType
                   ? typeDefaults.GetOrAdd(type, Activator.CreateInstance)
                   : null;
            }
        }
    }
    
  • 79

    选择的答案是一个很好的答案,但要小心返回的对象 .

    string test = null;
    string test2 = "";
    if (test is string)
         Console.WriteLine("This will never be hit.");
    if (test2 is string)
         Console.WriteLine("Always hit.");
    

    推断...

    string test = GetDefault(typeof(string));
    if (test is string)
         Console.WriteLine("This will never be hit.");
    
  • 54

    表达式可以在这里提供帮助:

    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();
        }
    

    我没有测试这个片段,但我认为它应该为引用类型生成“类型”空值 .

  • 22

    暂时找不到任何简单而优雅的东西,但我有一个想法:如果你知道你想要设置的属性的类型,你可以编写自己的 default(T) . 有两种情况 - T 是值类型, T 是引用类型 . 你可以通过检查 T.IsValueType 来看到这一点 . 如果 T 是引用类型,则只需将其设置为 null 即可 . 如果 T 是值类型,那么它将具有默认的无参数构造函数,您可以调用它来获取"blank"值 .

  • 94

    我做同样的事情 .

    //in MessageHeader 
       private void SetValuesDefault()
       {
            MessageHeader header = this;             
            Framework.ObjectPropertyHelper.SetPropertiesToDefault<MessageHeader>(this);
       }
    
    //in ObjectPropertyHelper
       public static void SetPropertiesToDefault<T>(T obj) 
       {
                Type objectType = typeof(T);
    
                System.Reflection.PropertyInfo [] props = objectType.GetProperties();
    
                foreach (System.Reflection.PropertyInfo property in props)
                {
                    if (property.CanWrite)
                    {
                        string propertyName = property.Name;
                        Type propertyType = property.PropertyType;
    
                        object value = TypeHelper.DefaultForType(propertyType);
                        property.SetValue(obj, value, null);
                    }
                }
        }
    
    //in TypeHelper
        public static object DefaultForType(Type targetType)
        {
            return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
        }
    
  • 0

    相当于Dror的答案,但作为一种扩展方法:

    namespace System
    {
        public static class TypeExtensions
        {
            public static object Default(this Type type)
            {
                object output = null;
    
                if (type.IsValueType)
                {
                    output = Activator.CreateInstance(type);
                }
    
                return output;
            }
        }
    }
    
  • 2
    /// <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;
        }
    
  • 632

    稍微调整@Rob Fonseca-Ensor's solution:以下扩展方法也适用于.Net标准,因为我使用GetRuntimeMethod而不是GetMethod .

    public static class TypeExtensions
    {
        public static object GetDefault(this Type t)
        {
            var defaultValue = typeof(TypeExtensions)
                .GetRuntimeMethod(nameof(GetDefaultGeneric), new Type[] { })
                .MakeGenericMethod(t).Invoke(null, null);
            return defaultValue;
        }
    
        public static T GetDefaultGeneric<T>()
        {
            return default(T);
        }
    }
    

    ...对于那些关心质量的人进行相应的单元测试:

    [Fact]
    public void GetDefaultTest()
    {
        // Arrange
        var type = typeof(DateTime);
    
        // Act
        var defaultValue = type.GetDefault();
    
        // Assert
        defaultValue.Should().Be(default(DateTime));
    }
    

相关问题