Programmatic equivalent of default(Type)
我使用反射来循环遍历
- 对于值类型,使用Activator.CreateInstance,它应该可以正常工作。
- 使用引用类型时,只返回空值
1 2 3 4 5 6 7 8 | public static object GetDefault(Type type) { if(type.IsValueType) { return Activator.CreateInstance(type); } return null; } |
在.NET标准等较新版本中,
为什么不调用返回带有反射的默认值(T)的方法?任何类型的getdefault都可以用于:
1 2 3 4 5 6 7 8 9 | public object GetDefault(Type t) { return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null); } public T GetDefaultGeneric<T>() { return default(T); } |
您可以使用
如果您使用的是.NET 4.0或更高版本,并且您想要的编程版本不是代码外定义的规则的编码,那么您可以创建一个
下面的扩展方法是取一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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()(); } |
您还应该基于
你为什么说仿制药已经过时了?
1 2 3 4 5 6 7 8 9 10 | 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解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } } } |
选择的答案是一个很好的答案,但是要小心返回的对象。
1 2 3 4 5 6 |
外推…
1 2 3 |
表达式可以帮助您:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(); } |
我没有测试这个片段,但我认为它应该为引用类型生成"类型化"的空值。
我做同样的工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //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; } |
现在还找不到任何简单而优雅的东西,但我有一个想法:如果你知道你想要设置的属性的类型,你可以写自己的
相当于德罗的答案,但作为扩展方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } } } |
稍微调整一下@rob fonseca ensor的解决方案:以下扩展方法也适用于.NET标准,因为我使用getruntimemethod而不是getmethod。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } } |
…对那些关心质量的人进行相应的单元测试:
1 2 3 4 5 6 7 8 9 10 11 12 | [Fact] public void GetDefaultTest() { // Arrange var type = typeof(DateTime); // Act var defaultValue = type.GetDefault(); // Assert defaultValue.Should().Be(default(DateTime)); } |
1 2 3 4 5 6 7 8 | /// <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; } |