程序化等效的默认(Type)

我正在使用反射来循环Type的属性,并将某些类型设置为默认值。 现在,我可以在类型上进行切换,并明确地设置default(Type) ,但我宁愿在一行中做。 是否有程序化的默认值?

  • 在值类型的情况下使用Activator.CreateInstance ,它应该工作正常。
  • 当使用引用类型时只返回null
 public static object GetDefault(Type type) { if(type.IsValueType) { return Activator.CreateInstance(type); } return null; } 

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

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

您可以使用PropertyInfo.SetValue(obj, null) 。 如果调用一个值类型,它会给你默认的。 在.NET 4.0和.NET 4.5中记录了此行为。

如果您使用的是.NET 4.0或更高版本,并且需要一个编程版本,而不是在代码之外定义的规则的编译 ,则可以创建一个Expression ,编译并在运行中运行它。

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

 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实例调用这个值,并且不要一直使用它,缓存占用的内存可能会超过它的好处。

为什么说泛型不在照片中?

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

这是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; } } } 

选择的答案是一个很好的答案,但要注意返回的对象。

 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."); 

表达式可以在这里帮助:

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

我没有测试这个片段,但我认为它应该产生“输入”为参考类型的空值。

目前找不到任何简单而优雅的东西,但我有一个想法:如果你知道你想要设置的属性的类型,你可以编写自己的default(T) 。 有两种情况 – T是值类型, T是引用类型。 你可以通过检查T.IsValueType来看到这个。 如果T是一个引用类型,那么你可以简单地将它设置为null 。 如果T是一个值类型,那么它将有一个默认的无参数构造函数,您可以调用以获得“空白”值。

我做这样的相同的任务。

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

等同于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; } } } 
  /// <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; }