93

I want to get the PropertyInfo for a specific property. I could use:

foreach(PropertyInfo p in typeof(MyObject).GetProperties())
{
    if ( p.Name == "MyProperty") { return p }
}

But there must be a way to do something similar to

typeof(MyProperty) as PropertyInfo

Is there? Or am I stuck doing a type-unsafe string comparison?

Cheers.

bluish
  • 26,356
  • 27
  • 122
  • 180
tenpn
  • 4,556
  • 5
  • 43
  • 63

5 Answers5

141

There is a .NET 3.5 way with lambdas/Expression that doesn't use strings...

using System;
using System.Linq.Expressions;
using System.Reflection;

class Foo
{
    public string Bar { get; set; }
}
static class Program
{
    static void Main()
    {
        PropertyInfo prop = PropertyHelper<Foo>.GetProperty(x => x.Bar);
    }
}
public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}
John Paul
  • 827
  • 2
  • 6
  • 16
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Nice solution but unfortunately I'm not using .NET3.5. Still, tick! – tenpn Jan 29 '09 at 13:22
  • 1
    In 2.0, Vojislav Stojkovic's answer is the closest you can get. – Marc Gravell Jan 29 '09 at 13:45
  • 4
    one question : why is there a test on "body is LambdaExpression" before it extracts .Body property ? Isn't selector always a LambdaExpression ? – tigrou Apr 26 '12 at 08:02
  • @tigrou quite possibly just an oversight, and perhaps me borrowing existing code that worked against just `Expression` – Marc Gravell Apr 26 '12 at 08:24
  • @MarcGravell this implementation is not very sound. You do not get the correct property info in case of `PropertyHelper.GetProperty(x => x.BaseProperty);`. See http://stackoverflow.com/questions/6658669/lambda-expression-not-returning-expected-memberinfo – nawfal Dec 13 '13 at 11:45
79

You can use the new nameof() operator that is part of C# 6 and available in Visual Studio 2015. More info here.

For your example you would use:

PropertyInfo result = typeof(MyObject).GetProperty(nameof(MyObject.MyProperty)) ?? throw new Exception();

The compiler will convert nameof(MyObject.MyProperty) to the string "MyProperty" but you gain the benefit of being able to refactor the property name without having to remember to change the string because Visual Studio, ReSharper, and the like know how to refactor nameof() values.

Jon Hallin
  • 508
  • 3
  • 9
Kevin Kalitowski
  • 6,829
  • 4
  • 36
  • 52
  • 2
    If would be arguably a little bit clearer if your example began with `PropertyInfo result =` instead of `var result =`. – DavidRR Jan 17 '17 at 20:13
  • That won't compile though, unless you add `?? throw new Exception()` at the end, since the compiler still thinks it could return `null` – Jon Hallin Jan 26 '23 at 12:53
13

You can do this:

typeof(MyObject).GetProperty("MyProperty")

However, since C# doesn't have a "symbol" type, there's nothing that will help you avoid using string. Why do you call this type-unsafe, by the way?

Vojislav Stojkovic
  • 8,043
  • 4
  • 35
  • 48
  • 40
    Because it's not evaluated at compile time? If I changed my property name or typo'd the string I wouldn't know until the code ran. – tenpn Jan 29 '09 at 13:22
2

This is probably the best way:

public static class TypeExtensions
    {
        public static PropertyInfo? GetProperty<T, TValue>(this T type, Expression<Func<T, TValue>> selector) where T : class
        {
            Expression expression = selector.Body;

            return expression.NodeType == ExpressionType.MemberAccess ? (PropertyInfo)((MemberExpression)expression).Member : null;
        }
    }

Usage:

myObject.GetProperty(opt => opt.PropertyName);
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 07 '22 at 00:07
  • This indeed seems like an easy quick hack, example of usage: myObj.GetProperty(x=>x.property) – L4marr Oct 31 '22 at 13:11
1

Reflection is used for runtime type evaluation. So your string constants cannot be verified at compile time.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 6
    That is what OP is trying to avoid. Not sure if this answers the question. – nawfal Dec 13 '13 at 11:42
  • Good point regarding compile time vs run time and the original intent of the OP though avoiding hardcoded strings still seems to be the cleanest solution - avoids the possibility of typos, allows for easier refactoring and makes for cleaner code style. – Brian Sweeney Oct 16 '14 at 14:18