.NET-получить значение по умолчанию для отраженного PropertyInfo
это действительно ставит меня в тупик сегодня. Я уверен, что это не так сложно, но у меня есть система.Отображение.Объект PropertyInfo. Я хочу установить его значение на основе результата поиска в базе данных (подумайте ORM, сопоставляя столбец со свойством).
моя проблема в том, что если возвращаемое значение DB равно DBNull, я просто хочу установить значение свойства по умолчанию, то же самое, что и вызов:
value = default(T); // where T is the type of the property.
однако метод 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);
однако, если тип string, это присвоит значение " new String ()", но я действительно хочу" null", что и" default(string) " вернет.
так чего же мне здесь не хватает? Я полагаю, что действительно хакерским способом было бы создать новый экземпляр типа myObj и скопировать свойство, но это просто кажется глупый...
object myObj = ???;
PropertyInfo myPropInf = ???;
var blank = Activator.CreateInstance(myObj.GetType());
object defaultValue = myPropInf.GetValue(blank, null);
myPropInf.SetValue(myObj, defaultValue, null);
Я бы предпочел не тратить память, чтобы сделать новый экземпляр, просто чтобы получить значение по умолчанию для свойства, хотя. Кажется очень расточительным.
какие идеи?
6 ответов:
Я верю, если вы просто делаете
prop.SetValue(obj,null,null);
Если это valuetype, он установит его в значение по умолчанию, если это ссылочный тип, он установит его в null.
трюк "null" установит его на ноль значение для типа, которое не обязательно совпадает с значением по умолчанию для свойства. Во-первых, если это новый объект, почему бы просто не оставить его в покое? Кроме того, используйте
TypeDescriptor
:PropertyDescriptor prop = TypeDescriptor.GetProperties(foo)["Bar"]; if (prop.CanResetValue(foo)) prop.ResetValue(foo);
это уважает как
[DefaultValue]
иReset{name}()
шаблоны (как используется при привязке и сериализации), что делает его очень универсальным и многоразовым.если вы делаете много этого, вы также можете получить повышение производительности с помощью
TypeDescriptor
вместо отражения, повторно используяPropertyDescriptorCollection
и с помощью HyperDescriptor (тот же код, но много быстрее, чем рефлексия или rawTypeDescriptor
).
попробуйте следующие методы, которые я написал и протестировал против тысяч типов:
/// <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).
наслаждайтесь!
это более полированная версия, которая поддерживает функциональность среды выполнения .NET без добавления ненужного пользовательского кода.
Примечание: этот код написан для .NET 3.5 С ПАКЕТОМ ОБНОВЛЕНИЯ 1
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();
Рашад Ривера (OmegusPrime.com)
Я знаю, что это старый пост, но мне нравится этот поворот в ответе Дарина Димитрова. Сначала он проверяет все атрибуты DefualtValue, а затем использует ответ Дарина Димитрова:
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; }