如何获得强类型给定类型的 属性 名称?
How to get a property name of a given type strongly typed?
我希望能够使用强类型语法检索 属性 类型的名称。
我已经有一个函数来获取实例的 属性 名称:
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)
我该怎么做?
您可以重写您的方法以在不创建实例的情况下使用它:
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;
}
}
请注意,return 类型不必是强类型,它可以只是 object
。
@abatishchev 示例仅在 Wheels
是引用类型时才有效。
如果你有以下情况
public class Car
{
public int ID;
}
然后你尝试调用这个
var prop = ReflectionHelper.PropertyName<Car>(x => x.ID);
您将得到以下异常
InvalidCastException: Unable to cast object of type
'System.Linq.Expressions.UnaryExpression' to type
'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;
}
}
在 C# 6 及更高版本中,using static
的语法优势可以使此类方法的用法更具可读性。它还将为您提供早期绑定/编译时检查,因此 CodeLens 将向您展示您的 属性 的用法,这些用法曾被引用为字符串文字(就像在周围浮动的许多数据绑定代码中一样)。这使得重构 变得更容易 当你不得不重命名属性时。
此处的代码基于@abatishchev 的回答,因为在这种情况下(您没有相关类型的实例),使用扩展方法会使代码 更多 冗长,不少。
PropertyName
方法中还有一个额外的行来处理@pedro-faustino 关于转换 UnaryExpression 的异常的观点。 (如果该方法在 propertyExpression
参数中有第二个类型参数,则不需要 return 类型,例如 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));
}
}
}
我希望能够使用强类型语法检索 属性 类型的名称。 我已经有一个函数来获取实例的 属性 名称:
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)
我该怎么做?
您可以重写您的方法以在不创建实例的情况下使用它:
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;
}
}
请注意,return 类型不必是强类型,它可以只是 object
。
@abatishchev 示例仅在 Wheels
是引用类型时才有效。
如果你有以下情况
public class Car
{
public int ID;
}
然后你尝试调用这个
var prop = ReflectionHelper.PropertyName<Car>(x => x.ID);
您将得到以下异常
InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type '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;
}
}
在 C# 6 及更高版本中,using static
的语法优势可以使此类方法的用法更具可读性。它还将为您提供早期绑定/编译时检查,因此 CodeLens 将向您展示您的 属性 的用法,这些用法曾被引用为字符串文字(就像在周围浮动的许多数据绑定代码中一样)。这使得重构 变得更容易 当你不得不重命名属性时。
此处的代码基于@abatishchev 的回答,因为在这种情况下(您没有相关类型的实例),使用扩展方法会使代码 更多 冗长,不少。
PropertyName
方法中还有一个额外的行来处理@pedro-faustino 关于转换 UnaryExpression 的异常的观点。 (如果该方法在 propertyExpression
参数中有第二个类型参数,则不需要 return 类型,例如 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));
}
}
}