我使用反射来循环一个类型的属性,并将某些类型设置为默认值。现在,我可以在类型上进行切换,并显式地设置默认(type),但我宁愿在一行中完成。在编程中是否存在与默认设置相同的功能?


当前回答

对@Rob Fonseca-Ensor的解决方案进行了轻微调整:下面的扩展方法也适用于. net Standard,因为我使用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));
}

其他回答

我像这样做同样的任务。

//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;
    }

下面的表达可以帮助你:

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

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

如果你使用的是。net 4.0或更高版本,并且你想要一个程序化的版本,而不是在代码之外定义规则的编码,你可以创建一个Expression,编译并动态运行它。

下面的扩展方法将接受一个Type,并通过Expression类的default方法获取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实例调用这个函数,并且不要经常使用它,那么缓存所消耗的内存可能会超过它带来的好处。

为什么不调用带有反射返回default(T)的方法呢?你可以使用任何类型的GetDefault:

    public object GetDefault(Type t)
    {
        return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
    }

    public T GetDefaultGeneric<T>()
    {
        return default(T);
    }

如果是值类型,请使用Activator。CreateInstance,它应该可以正常工作。 当使用引用类型时,只返回null

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

在。net的新版本,如。net标准中,键入。IsValueType需要被写成type.GetTypeInfo().IsValueType