我希望能够使用强类型语法检索类型属性的名称。 我已经有了一个函数来获取实例的属性名称:
public static string PropertyName<T, TReturn>(this T obj, Expression<Func<T, TReturn>> property) where T : class
{
MemberExpression body = (MemberExpression) property.Body;
if (body == null) throw new ArgumentException("The provided expression did not point to a property.");
return body.Member.Name;
}
可以这样调用:
Car car = new Car();
car.PropertyName(x => x.Wheels) //returns "Wheels"
我试图创建另一个可以支持以下功能的功能:
Type t = Typeof(Car);
t.PropertyName(x => x.Wheels) //should return "Wheels"
或者只是(甚至更好!):
Car.PropertyName(x => x.Wheels)
我该怎么做?
答案 0 :(得分:7)
您可以在不创建实例的情况下重写方法以使用它:
var prop = ReflectionHelper.PropertyName<Car>(x => x.Wheels);
因为您不需要使用obj
,因为您不需要它:
public static class ReflectionHelper
{
public static string PropertyName<T>(Expression<Func<T, object>> property) where T : class
{
MemberExpression body = (MemberExpression)property.Body;
return body.Member.Name;
}
}
请注意,返回类型不必是强类型的,它可以只是object
。
答案 1 :(得分:1)
@abatishchev示例仅在Wheels
是引用类型的情况下有效。
如果您具有以下条件
public class Car
{
public int ID;
}
您尝试称呼它
var prop = ReflectionHelper.PropertyName<Car>(x => x.ID);
您将收到以下异常
InvalidCastException:无法转换类型的对象 键入“ System.Linq.Expressions.UnaryExpression” 'System.Linq.Expressions.MemberExpression'。
我认为这与将值类型传递给表达式有关,因此必须将其装箱到对象中。如果传递引用类型,则无需将其装箱成对象。
相反,您可以做的是:
var prop = ReflectionHelper.PropertyName((Car x) => x.ID);
public static class ReflectionHelper
{
public static string PropertyName<T, P>(Expression<Func<T, P>> property)
where T : class
{
MemberExpression body = (MemberExpression)property.Body;
return body.Member.Name;
}
}
答案 2 :(得分:1)
在C#6和更高版本中,using static
的句法优势可以使这种方法的用法更具可读性。它还将为您提供早期的绑定/编译时检查,因此CodeLens将向您显示对属性的用法,这些属性曾经被称为字符串文字(例如,在周围浮动的许多数据绑定代码中)。当您不得不重新命名属性时,这使得重构很多更加容易。
此处的代码基于@abatishchev的答案,因为在这种情况下(您没有相关类型的实例),使用扩展方法会使代码 more 变得冗长而不是更少
PropertyName
方法中还有一行额外内容,用于处理@ pedro-faustino关于强制转换UnaryExpression的异常的观点。 (如果该方法在propertyExpression
参数中有第二个类型参数,则返回类型为Expression<Func<T, TMember>>
,则不需要)。
也就是说,这是一个示例,说明如何使用这种策略以早期绑定方式绑定数据绑定:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using BusinessObjects.Vehicles;
using static MyCoolHelperMethods;
namespace Helpers
{
public static class MyCoolHelperMethods
{
public static string PropertyName<T>(Expression<Func<T, object>> propertyExpression) where T : class
{
var memberExpression = propertyExpression.Body as MemberExpression
?? (propertyExpression.Body as UnaryExpression)?.Operand as MemberExpression;
return memberExpression?.Member.Name;
}
}
}
namespace Application
{
using System.Windows.Forms;
public class Car
{
public string Make {get; set;}
public string Model {get; set;}
}
// imagine this is a form with textboxes for car Make and Model:
public partial class MyWindowsForm
{
public MyWindowsForm()
{
var car = new Car();
this.txtCarMake.DataBindings.Add(new Binding(
propertyName: PropertyName<TextBox>(x => x.Text),
dataSource: car,
dataMember: PropertyName<Car>(x => x.Make),
// formattingEnabled is needed to avoid invalid cast
// exceptions assigning the object property to the control:
formattingEnabled: true));
this.txtCarModel.DataBindings.Add(new Binding(
propertyName: PropertyName<TextBox>(x => x.Text),
dataSource: car,
dataMember: PropertyName<Car>(x => x.Model),
// formattingEnabled is needed to avoid invalid cast
// exceptions assigning the object property to the control:
formattingEnabled: true));
}
}
}