今天真的让我很难过。我确定它不是那么难,但我有一个System.Reflection.PropertyInfo对象。我想根据数据库查找的结果设置其值(想想ORM,将列映射回属性)。
我的问题是如果DB返回的值是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);
以上不编译。默认(类型)无效。我也考虑过这样做:
object myObj = ???;
PropertyInfo myPropInf = ???;
myPropInf.SetValue(myObj, Activator.CreateInstance(myPropInf.PropertyType), null);
但是,如果Type是字符串,那将赋值“new String()”,但我真的想要“null”,这就是“default(string)”将返回的内容。
那我在这里错过了什么? 我想一个非常hacky的方法是创建myObj的Type的新实例并将属性复制过来,但这看起来很愚蠢......
object myObj = ???;
PropertyInfo myPropInf = ???;
var blank = Activator.CreateInstance(myObj.GetType());
object defaultValue = myPropInf.GetValue(blank, null);
myPropInf.SetValue(myObj, defaultValue, null);
我宁愿不浪费内存来创建一个全新的实例,只是为了获得该属性的默认值。似乎非常浪费。
有什么想法吗?
答案 0 :(得分:50)
我相信如果你这样做
prop.SetValue(obj,null,null);
如果它是一个值类型,它会将它设置为默认值,如果它是一个引用类型,它会将它设置为null。
答案 1 :(得分:47)
object defaultValue = type.IsValueType ? Activator.CreateInstance(type) : null;
答案 2 :(得分:29)
“null”技巧会将其设置为类型的零值,该值不一定与属性的默认值相同。首先,如果它是一个新的对象,为什么不单独留下它?或者,使用TypeDescriptor
:
PropertyDescriptor prop = TypeDescriptor.GetProperties(foo)["Bar"];
if (prop.CanResetValue(foo)) prop.ResetValue(foo);
这同时尊重[DefaultValue]
和Reset{name}()
模式(由绑定和序列化使用),使其非常通用和可重复使用。
如果你正在做很多这样的事情,你可以使用TypeDescriptor
而不是反射来提升效果,方法是重复使用PropertyDescriptorCollection
并使用HyperDescriptor(相同的代码,但是多比refletion或raw TypeDescriptor
更快。
答案 3 :(得分:13)
尝试以下方法,我已经编写并针对数千种类型进行了测试:
/// <summary>
/// [ <c>public static T GetDefault< T >()</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<T>"/>
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 (i.e. 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");
}
GetDefault的第一个(通用)版本当然是C#的冗余版本,因为您可能只使用默认(T)关键字。
享受!
答案 4 :(得分:0)
这是一个更加精致的版本,可以维护.NET Runtime的功能,而无需添加任何不必要的自定义代码。
注意:此代码是为.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)
答案 5 :(得分:0)
我知道这是一个老帖子,但我喜欢Darin Dimitrov的回答。它首先检查任何DefualtValue属性,然后使用Darin Dimitrov's answer:
public static object GetDefaultValueForProperty(this PropertyInfo property)
{
var defaultAttr = property.GetCustomAttribute(typeof(DefaultValueAttribute));
if (defaultAttr != null)
return (defaultAttr as DefaultValueAttribute).Value;
var propertyType = property.PropertyType;
return propertyType.IsValueType ? Activator.CreateInstance(propertyType) : null;
}