如何获取特定属性的 PropertyInfo?

我想获取一个特定属性的 PropertyInfo,我可以使用:

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

但是一定有办法做类似的事情

typeof(MyProperty) as PropertyInfo

是吗? 还是我只能做类型不安全的字符串比较?

干杯。

73058 次浏览

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?

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

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();
}
}
}

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));

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.

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);