Jeff Dege
Jeff Dege

Reputation: 11700

Can I get PropertyInfo of a property without using its name?

I have a class that has a property, and that property has an attribute, and within the get{} or set{} of that property, I want to access that attribute.

Is there any way of doing this without having to reference the name of the property as a string? Does this work?

class MyClass
{
    [DefaultValue("This is my default")]
    public string MyProperty
    {
        get
        {
            string value = this.db.getMyProperty();
            if (value == null)
            {
                var myPropertyInfo = this.GetType().GetProperty("MyProperty");
                var myAttributeInfo = myPropertyInfo.GetCustomAttribute(
                    typeof (DefaultValueAttribute)) as DefaultValueAttribute;
                if (myAttributeInfo != null)
                    value = myAttributeInfo.defaultValue;
            }
            return value;
        }
    }
}

What causes me concern about this is that passing the name of the property is a violation of DRY, and makes it too easy to accidentally pass the wrong string.

How can I improve this code to remove duplication?

Upvotes: 0

Views: 391

Answers (3)

Felipe Oriani
Felipe Oriani

Reputation: 38608

Use MethodBase.GetCurrentMethod() to get the current reference from method or a property. In your case, use the Name property which will return a string get_MyProperty and remove the get_ part with substring, Try this:

[DefaultValue("This is my default")]
public string MyProperty
{
    get
    {
        string value = this.db.getMyProperty();
        if (value == null)
        {
            // get property name from GetCurrentMethod.
            // use the SubString to remove the "get_" that comes from .net internals
            var propertyName = MethodBase.GetCurrentMethod().Name.Substring(4);

            // keep your method
            var myPropertyInfo = this.GetType().GetProperty(propertyName);
            var myAttributeInfo = myPropertyInfo.GetCustomAttribute(
                typeof (DefaultValueAttribute)) as DefaultValueAttribute;
            if (myAttributeInfo != null)
                value = myAttributeInfo.defaultValue;
        }
        return value;
    }
}

Upvotes: 2

Scott Dorman
Scott Dorman

Reputation: 42516

You don't say what version of the Framework you're using, but if it's .NET 4.5 or later you can use CallerMemberName. Add the following method to MyClass:

private PropertyInfo GetProperty([CallerMemberName] string name = "")
{
   var myPropertyInfo = this.GetType().GetProperty(name);
   return myPropertyInfo;
}

Then, in MyProperty change

var myPropertyInfo = this.GetType().GetProperty("MyProperty");

to

var myPropertyInfo = this.GetProperty();

At runtime, the value for name parameter of GetProperty will be provided automatically for you.

Actually, if you're doing this a lot (and it's always the same attribute) you could simplify this even more:

private string GetDefaultValueForProperty([CallerMemberName] string name = "")
{
    string defaultValue = null;
    var myPropertyInfo = this.GetType().GetProperty(name);
    var myAttributeInfo = myPropertyInfo.GetCustomAttribute<DefaultValueAttribute>();
    if (myAttributeInfo != null)
    {
        defaultValue = (string)myAttributeInfo.Value;
    }

    return defaultValue;
}

Then the code in your property looks like this:

[DefaultValue("This is my default")]
public string MyProperty
{
    get
    {
        string value = this.db.getMyProperty();
        if (value == null)
        {
            value = GetDefaultValueForProperty();
        }
        return value;
    }
}

Upvotes: 3

Luaan
Luaan

Reputation: 63732

You can use an extension method like this:

public static TValue GetDefaultValue<TParent, TValue>
  (this TParent @this, Expression<Func<TParent, TValue>> e)
{
  var member = (e.Body as MemberExpression).Member;
  var attr = member.GetCustomAttribute(typeof (DefaultValueAttribute)) 
               as DefaultValueAttribute;

  return (TValue)attr.Value;
}

And now you only have to do this in your property:

return GetDefaultValue(i => i.MyProperty);

Nicer and with compile-time checks and it works with refactoring too :)

The extension method is really bare-bone, you want it to be safer, but the idea should be clear.

Upvotes: 1

Related Questions