在CSDN 上 看了一篇Daniel Cazzulinode的文章:Linq的超越
(原文链接http://blog.csdn.net/programmer_editor/archive/2006/09/29/1305859.aspx)
挺有意思的,自己也研究了一下.
题目可能没有说清楚,那么咱么现在考虑一个场景:
为了能够显示不同数据对象的数据,提高可复用性,你写了一个继承自DataGridView的控件,里面有一个Load()的公共方法,用来载入数据。
propertyNames 是一组要显示数据的属性名
headerText 是对应的Column的headerText
在Load()方法中,遍历items的每一个元素。并且用反射的方法,获取指定属性名的数据,显示在DataGridView里。
例如我们要显示一组人的姓名和年龄:
假如我们以后认为Name这个属性名并不好,并且想用NickName替代,利用VS强大的功能,很容易就可以完成重构,但是问题来了,我们还要手动去更改Load()调用的参数,因为我们传入的是固定的字符串,VS并不会自动的帮助我们进行更改。
在Lambda引入之前,我们是没有办法完成这个功能的,但是现在我们利用Lambda Expression便可以实现。
首先,设计一个类
下面这个方法是关键,我们传入一个Lambda表达式,她将返回一个MemberInfo,只是这个表达式是有要求的,她的形式是 "参数 => 成员调用"。
由于返回的是MemberInfo,是PropertyInfo,MethodInfo等的基类。而事实上,如果我们的"成员调用"是一个Property那么此方法实际上返回的就是一个PropertyInfo,我们只要将它转化一下就可以了。
下面是测试结果:
细心的你也许已经发现,其实我们传入的Lambda表达式并没有真正的被编译并且执行。所以假如我们要传入 "p=>p.someMethod(.....)" 而someMethod这个方法是有参数的,那么我们只需简单的传入一个 null 就可以了,就像这样"p=>p.someMethod(null,null...)" 。
至于GetMemberInfo<T>(..)方法为什么要那么实现,就留给读者自己动手试一下吧,只要在Debug状态下查看一下Expression的结构,自然就明白了。
(原文链接http://blog.csdn.net/programmer_editor/archive/2006/09/29/1305859.aspx)
挺有意思的,自己也研究了一下.
题目可能没有说清楚,那么咱么现在考虑一个场景:
为了能够显示不同数据对象的数据,提高可复用性,你写了一个继承自DataGridView的控件,里面有一个Load()的公共方法,用来载入数据。
public void LoadData(object[] items, string[] propertyNames, string[] headerText)
items 是某一个类型的对象数组。propertyNames 是一组要显示数据的属性名
headerText 是对应的Column的headerText
在Load()方法中,遍历items的每一个元素。并且用反射的方法,获取指定属性名的数据,显示在DataGridView里。
例如我们要显示一组人的姓名和年龄:
Load(Persons,
new string[] { "Name", "Age" },
new string[] { "姓名", "年龄" });)
new string[] { "Name", "Age" },
new string[] { "姓名", "年龄" });)
假如我们以后认为Name这个属性名并不好,并且想用NickName替代,利用VS强大的功能,很容易就可以完成重构,但是问题来了,我们还要手动去更改Load()调用的参数,因为我们传入的是固定的字符串,VS并不会自动的帮助我们进行更改。
在Lambda引入之前,我们是没有办法完成这个功能的,但是现在我们利用Lambda Expression便可以实现。
首先,设计一个类
public class TestClass
{
public string Name;
public string PName { set; get; }
public string GetName()
{
return Name;
}
public int Age;
public int PAge { set; get; }
public int GetAge()
{
return Age;
}
public TestClass GetInstance()
{
return new TestClass();
}
}
{
public string Name;
public string PName { set; get; }
public string GetName()
{
return Name;
}
public int Age;
public int PAge { set; get; }
public int GetAge()
{
return Age;
}
public TestClass GetInstance()
{
return new TestClass();
}
}
下面这个方法是关键,我们传入一个Lambda表达式,她将返回一个MemberInfo,只是这个表达式是有要求的,她的形式是 "参数 => 成员调用"。
由于返回的是MemberInfo,是PropertyInfo,MethodInfo等的基类。而事实上,如果我们的"成员调用"是一个Property那么此方法实际上返回的就是一个PropertyInfo,我们只要将它转化一下就可以了。
public static MemberInfo GetMemberInfo<T>(Expression<Func<T, object>> exp)
{
Expression texp = exp.Body;
if (texp.NodeType == ExpressionType.Convert)
texp = ((UnaryExpression)texp).Operand;
if (texp.NodeType == ExpressionType.Call)
return ((MethodCallExpression)texp).Method;
if (texp.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression)texp).Member;
return null;
}
来做一个测试{
Expression texp = exp.Body;
if (texp.NodeType == ExpressionType.Convert)
texp = ((UnaryExpression)texp).Operand;
if (texp.NodeType == ExpressionType.Call)
return ((MethodCallExpression)texp).Method;
if (texp.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression)texp).Member;
return null;
}
static void Main(string[] args)
{
Console.WriteLine(GetMemberInfo<TestClass>(p => p.Age).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.PAge).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetAge()).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.Name).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.PName).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetName()).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetInstance()).Name);
}
{
Console.WriteLine(GetMemberInfo<TestClass>(p => p.Age).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.PAge).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetAge()).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.Name).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.PName).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetName()).Name);
Console.WriteLine(GetMemberInfo<TestClass>(p => p.GetInstance()).Name);
}
下面是测试结果:
细心的你也许已经发现,其实我们传入的Lambda表达式并没有真正的被编译并且执行。所以假如我们要传入 "p=>p.someMethod(.....)" 而someMethod这个方法是有参数的,那么我们只需简单的传入一个 null 就可以了,就像这样"p=>p.someMethod(null,null...)" 。
至于GetMemberInfo<T>(..)方法为什么要那么实现,就留给读者自己动手试一下吧,只要在Debug状态下查看一下Expression的结构,自然就明白了。