程序化等效的默认(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; }