在CSDN 上 看了一篇Daniel Cazzulinode的文章:Linq的超越
(原文链接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[] "姓名""年龄" });)

    假如我们以后认为Name这个属性名并不好,并且想用NickName替代,利用VS强大的功能,很容易就可以完成重构,但是问题来了,我们还要手动去更改Load()调用的参数,因为我们传入的是固定的字符串,VS并不会自动的帮助我们进行更改。
    在Lambda引入之前,我们是没有办法完成这个功能的,但是现在我们利用Lambda Expression便可以实现。

    首先,设计一个类
        public class TestClass
        
{
            
public string Name;
            
public string PName setget; }
            
public string GetName()
            
{
                
return Name;
            }

            
public int Age;
            
public int PAge setget; }
            
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;
        }
    来做一个测试
        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);
        }

    下面是测试结果:
 

    细心的你也许已经发现,其实我们传入的Lambda表达式并没有真正的被编译并且执行。所以假如我们要传入 "p=>p.someMethod(.....)" 而someMethod这个方法是有参数的,那么我们只需简单的传入一个 null 就可以了,就像这样"p=>p.someMethod(null,null...)" 。 

    至于GetMemberInfo<T>(..)方法为什么要那么实现,就留给读者自己动手试一下吧,只要在Debug状态下查看一下Expression的结构,自然就明白了。
posted on 2007-12-01 18:25  yujiasw  阅读(424)  评论(0编辑  收藏  举报