Reputation: 2557
I have a property, (example shown below).
[DefaultValue(false)]
public bool MyProperty {
get {
return myVal;
}
set {
myVal=value;
}
}
The situation I'm using this is to make sure it shows up as bold in the a PropertyGrid if the default value is not set.
I find it incredibly annoying that in my constructor, I have to set the initial value of my property, and hope that they match up.
Is it possible to have my constructor "discover" the default value of a given property, and set it accordingly? Something like:
myctor()
{
myVal = GetDefaultValueProperty<bool>("MyProperty");
}
Upvotes: 6
Views: 6401
Reputation: 4975
Here's a generic extension method based on Paul Turner's answer. It will work for any member of any class.
public static bool TryGetDefaultValue<TSource, TResult>(this TSource _, Expression<Func<TSource, TResult>> expression, out TResult result)
{
if (((MemberExpression)expression.Body).Member.GetCustomAttribute(typeof(DefaultValueAttribute)) is DefaultValueAttribute attribute)
{
result = (TResult)attribute.Value;
return true;
}
result = default;
return false;
}
Alternatively, you're OK with the default value being returned if the attribute was not found, use this:
public static TResult GetDefaultValue<TSource, TResult>(this TSource _, Expression<Func<TSource, TResult>> expression)
{
if (((MemberExpression)expression.Body).Member.GetCustomAttribute(typeof(DefaultValueAttribute)) is DefaultValueAttribute attribute)
{
return (TResult)attribute.Value;
}
return default;
}
You could also modify it to throw an exception if the attribute wasn't found.
Upvotes: 0
Reputation: 39625
You can use the following code to get the metadata you're after.
public static T GetDefaultValue<T>(string propertyName)
{
var property = typeof(MyClass).GetProperty(propertyName);
var attribute = property
.GetCustomAttribute(typeof(DefaultValueAttribute))
as DefaultValueAttribute;
if(attribute != null)
{
return (T)attribute.Value;
}
}
If you want to do something really cool, you can do this with a Lambda expression:
public static T GetDefaultValue<T>(
Expression<Func<T, MyClass>> propertySelector)
{
MemberExpression memberExpression = null;
switch (expression.Body.NodeType)
{
case ExpressionType.MemberAccess:
// This is the default case where the
// expression is simply member access.
memberExpression
= expression.Body as MemberExpression;
break;
case ExpressionType.Convert:
// This case deals with conversions that
// may have occured due to typing.
UnaryExpression unaryExpression
= expression.Body as UnaryExpression;
if (unaryExpression != null)
{
memberExpression
= unaryExpression.Operand as MemberExpression;
}
break;
}
MemberInfo member = memberExpression.Member;
// Check for field and property types.
// All other types are not supported by attribute model.
switch (member.MemberType)
{
case MemberTypes.Property:
break;
default:
throw new Exception("Member is not property");
}
var property = (PropertyInfo)member;
var attribute = property
.GetCustomAttribute(typeof(DefaultValueAttribute))
as DefaultValueAttribute;
if(attribute != null)
{
return (T)attribute.Value;
}
}
Usage is then:
myctor()
{
myVal = GetDefaultValue(x => x.MyProperty);
}
Upvotes: 9
Reputation: 887453
You can call the GetProperty
method to find the property, then call GetCustomAttributes(typeof(DefaultValueAttribute)
(and cast its result) to get the attribute applied.
Upvotes: 6