在.net FrameWork 3.5中,我们可以使用下面提到的代码获取属性信息。
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();
}
}
}
这也可以通过创建类的实例并访问Property Member来完成。那么物业信息的优势是什么?
答案 0 :(得分:4)
PropertyInfo
用于获取类属性的信息。不需要创建实例。优点是它消除了输入错误的可能性。
Expressions
是完全不同的概念(内部使用Reflection)。表达式用于将方法体表示为树结构。这允许在运行时创建/调整方法定义的灵活性。
表达式的这种功能由Queryable类利用,以在远程源上构建/执行动态查询。
实施例,
考虑INotifyPropertyChanged
接口。它用于财产变更通知。
通常的实现将属性名称作为字符串参数。因此,在运行时检测到键入错误。此外,重构可能会破坏代码(虽然智能重构工具可以解决这个问题)。
void RaisePropertyChanged(PropertyChangedEventArgs args)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public string Name
{
set
{
_name = value;
RaisePropertyChanged("Name"); // Property name is specified as string
}
}
更好的实现(虽然效率不高)将属性名称设为Expression
。
void RaisePropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
var handler = PropertyChanged;
if (handler != null)
{
MemberExpression body = selectorExpression.Body as MemberExpression;
handler(this, new PropertyChangedEventArgs(body.Member.Name));
}
}
public string Name
{
set
{
_name = value;
RaisePropertyChanged( () => this.Name); // Property is specified instead of name that removes typing error
}
}
答案 1 :(得分:0)
通过剖析表达式获取PropertyInfo的优点是它为您提供了编译时检查并提供了更好的重构支持。
例如,如果将属性的名称从Bar更改为Barr,则代码将不再编译,从而允许您在不实际运行应用程序的情况下捕获无效的成员访问错误。
如果您事先知道需要访问哪个属性,那么表达式就可以了。
我发现表达式在数据绑定方案中特别有用,在这种情况下,您需要指定要绑定到网格列或列表控件的属性的名称。在这种情况下使用表达式可以降低维护成本。
以下是使用表达式使用您自己的PropertyHelper类执行网格列格式化的示例。
跳转到GridForm.FormatGrid()以查看重要位。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;
namespace ExpressionSample
{
public class TestEntity
{
public int ID { get; set; }
public string Text { get; set; }
public decimal Money { get; set; }
}
public partial class GridForm : Form
{
public GridForm()
{
this.InitializeComponent();
}
private void GridForm_Load(object sender, EventArgs e)
{
this.FillGrid();
this.FormatGrid();
}
private void FillGrid()
{
this.DataGridView.DataSource = TestDataProducer.GetTestData();
}
private void FormatGrid()
{
var redCellStyle = new DataGridViewCellStyle() { ForeColor = Color.Red };
var moneyCellStyle = new DataGridViewCellStyle() { Format = "$###,###,##0.00" };
this.GridColumn(e => e.ID).Visible = false;
this.GridColumn(e => e.Text).DefaultCellStyle = redCellStyle;
this.GridColumn(e => e.Money).DefaultCellStyle = moneyCellStyle;
}
private DataGridViewColumn GridColumn<TProperty>(Expression<Func<TestEntity, TProperty>> expr)
{
var propInfo = PropertyHelper<TestEntity>.GetProperty(expr);
var column = this.DataGridView.Columns[propInfo.Name];
return column;
}
}
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();
}
}
}
public static class TestDataProducer
{
public static IList<TestEntity> GetTestData()
{
var entities = new List<TestEntity>();
for (var i = 1; i <= 10; i++)
{
var testEntity = new TestEntity {
ID = i,
Text = "Entity " + i.ToString(),
Money = i * 100m
};
entities.Add(testEntity);
}
return entities;
}
}
}