.NET – 获取reflection的PropertyInfo的默认值

今天真的很难过 我确定它不那么难,但我有一个System.Reflection.PropertyInfo对象。 我想根据数据库查找的结果设置它的值(想想ORM,将列映射回属性)。

我的问题是,如果数据库返回值是DBNull,我只想将属性值设置为其默认值,就像调用:

value = default(T); // where T is the type of the property. 

然而,如果你给它一个Type,那么default()方法将不会被编译,这就是我所拥有的:

 object myObj = ???; // doesn't really matter. some arbitrary class. PropertyInfo myPropInf = ???; // the reflection data for a property on the myObj object. myPropInf.SetValue(myObj, default(myPropInf.PropertyType), null); 

以上不编译。 默认(Type)无效。 我也想过这样做:

 object myObj = ???; PropertyInfo myPropInf = ???; myPropInf.SetValue(myObj, Activator.CreateInstance(myPropInf.PropertyType), null); 

但是,如果types是string,那将分配值“new String()”,但我真的想要“null”,这是“默认(string)”将返回。

那么我在这里错过了什么? 我想一个非常冒险的方法是创build一个myObj的types的新实例,并复制属性,但这似乎是愚蠢的…

 object myObj = ???; PropertyInfo myPropInf = ???; var blank = Activator.CreateInstance(myObj.GetType()); object defaultValue = myPropInf.GetValue(blank, null); myPropInf.SetValue(myObj, defaultValue, null); 

我宁愿不浪费内存来创build一个新的实例,只是为了获得属性的默认值。 看起来非常浪费。

有任何想法吗?

我相信如果你只是这样做

 prop.SetValue(obj,null,null); 

如果它是一个值types,它会将其设置为默认值,如果它是一个引用types,它会将其设置为null。

 object defaultValue = type.IsValueType ? Activator.CreateInstance(type) : null; 

“空”技巧将把它设置为types的值,这不一定与属性的默认值相同。 首先,如果这是一个新的对象,为什么不把它放在一边呢? 或者,使用TypeDescriptor

 PropertyDescriptor prop = TypeDescriptor.GetProperties(foo)["Bar"]; if (prop.CanResetValue(foo)) prop.ResetValue(foo); 

这既考虑了[DefaultValue]又考虑了Reset{name}()模式(用于绑定和序列化),使得它非常灵活和可重用。

如果你正在做很多这样的事情,你可以使用TypeDescriptor而不是reflection,通过重用PropertyDescriptorCollection和使用HyperDescriptor (相同的代码,但比reflection或原始TypeDescriptor快得多)来获得性能提升。

尝试下面的方法,我已经编写和testing了成千上万的types:

  /// <summary> /// [ <c>public static T GetDefault&lt; T &gt;()</c> ] /// <para></para> /// Retrieves the default value for a given Type /// </summary> /// <typeparam name="T">The Type for which to get the default value</typeparam> /// <returns>The default value for Type T</returns> /// <remarks> /// If a reference Type or a System.Void Type is supplied, this method always returns null. If a value type /// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an /// exception. /// </remarks> /// <seealso cref="GetDefault(Type)"/> public static T GetDefault<T>() { return (T) GetDefault(typeof(T)); } /// <summary> /// [ <c>public static object GetDefault(Type type)</c> ] /// <para></para> /// Retrieves the default value for a given Type /// </summary> /// <param name="type">The Type for which to get the default value</param> /// <returns>The default value for <paramref name="type"/></returns> /// <remarks> /// If a null Type, a reference Type, or a System.Void Type is supplied, this method always returns null. If a value type /// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an /// exception. /// </remarks> /// <seealso cref="GetDefault&lt;T&gt;"/> public static object GetDefault(Type type) { // If no Type was supplied, if the Type was a reference type, or if the Type was a System.Void, return null if (type == null || !type.IsValueType || type == typeof(void)) return null; // If the supplied Type has generic parameters, its default value cannot be determined if (type.ContainsGenericParameters) throw new ArgumentException( "{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type + "> contains generic parameters, so the default value cannot be retrieved"); // If the Type is a primitive type, or if it is another publicly-visible value type (ie struct), return a // default instance of the value type if (type.IsPrimitive || !type.IsNotPublic) { try { return Activator.CreateInstance(type); } catch (Exception e) { throw new ArgumentException( "{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe Activator.CreateInstance method could not " + "create a default instance of the supplied value type <" + type + "> (Inner Exception message: \"" + e.Message + "\")", e); } } // Fail with exception throw new ArgumentException("{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type + "> is not a publicly-visible type, so the default value cannot be retrieved"); } 

对于C#,GetDefault的第一个(通用)版本当然是多余的,因为您可能只使用默认(T)关键字。

请享用!

这是一个更加精美的版本,可以在不添加任何不必要的自定义代码的情况下维护.NET运行时的function。

注意:为.NET 3.5 SP1编写的代码

 namespace System { public static class TypedDefaultExtensions { public static object ToDefault(this Type targetType) { if (targetType == null) throw new NullReferenceException(); var mi = typeof(TypedDefaultExtensions) .GetMethod("_ToDefaultHelper", Reflection.BindingFlags.Static | Reflection.BindingFlags.NonPublic); var generic = mi.MakeGenericMethod(targetType); var returnValue = generic.Invoke(null, new object[0]); return returnValue; } static T _ToDefaultHelper<T>() { return default(T); } } 

}

用法:

 PropertyInfo pi; // set to some property info object defaultValue = pi.PropertyType.ToDefault(); public struct MyTypeValue { public int SomeIntProperty { get; set; } var reflectedType = typeof(MyTypeValue); object defaultValue2 = reflectedType.ToDefault(); 

Rashad Rivera(OmegusPrime.com)