lambda 表达式作为属性

Posted

技术标签:

【中文标题】lambda 表达式作为属性【英文标题】:lambda Expression as a property 【发布时间】:2011-11-23 13:27:21 【问题描述】:

我有一个非强类型且依赖于反射的工作设置。

我有课,比如说

class Person

    public string FirstName get ; set;
    public string LastName get; set;
    public int Age get; set;
    ...  
    // some more public properties

class CellInfo 
     public string Title get; set;
     public string FormatString get; set;

我有一本这样的字典

Dictionary<string, CellInfo> fields = new Dictionary<string, CellInfo>();
fields.Add("FirstName", new CellInfo Title = "First Name", FormatString = "Foo");
fields.Add("LastName", new CellInfo Title = "Last Name", FormatString = "Bar");

这是一个简单的字典,包含属性名称和一些关于它们的信息。 我将字典传递给另一个处理 Person 实例的模块,我这样做了

Dictionary<string, CellInfo> fields = SomeMethodToGetDictionary();
foreach(Person p in someCollection)

    foreach(var field in fields)
     
       object cellValue = type(Person).GetProperty(field.Key).GetValue(p, null);
       // use cellValue and info on field from field.Value somewhere.
       ...
    
 

这种为字段名称传递字符串并使用反射的方法有效,但我想知道是否有一种强类型的方法可以做到这一点。

我想到的是拥有一个存储 linq 表达式的属性,就像这样

fields.Add("FirstName", new CellInfo 
                   
                      Title = "First Name", 
                      FormatString = "Foo",
                      EvalExpression = p => p.FirstName
                   );

在使用过程中,以某种方式在人员对象上使用EvalExpression 并获取属性值。我不知道从哪里开始,也不知道拥有这样一个可评估的属性会是什么样的语法。我是函数委托和表达式树的新手,我什至不知道要搜索的正确关键字。希望我的描述清楚;如果没有,请告诉我,必要时我会详细说明。 任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

使用委托:

class CellInfo 
    public string Title get; set; 
    public string FormatString get; set; 
    public Func<Person, object> EvalExpression  get; set; 

那么你的 lambda 输入就可以工作了……

【讨论】:

【参考方案2】:

如果您说强类型化是这个意思,您可以尝试这样的方法,而不必将属性名称编码为字符串:

class CellInfo<T>

    public string Title  get; set; 
    public string FormatString  get; set; 
    public Func<T, object> Selector  get; set; 


Dictionary<string, CellInfo<Person>> dict = new Dictionary<string, CellInfo<Person>>();

dict.Add("LastName", new CellInfo<Person>  Selector = p => p.LastName );
dict.Add("Age", new CellInfo<Person>  Selector = p => p.Age );

foreach (Person p in someCollection)

    foreach (var cellInfo in dict)
    
        object value = cellInfo.Value.Selector(p);
    

【讨论】:

【参考方案3】:

我认为代表是您所需要的。像这样的:

public delegate string EvalExpressionDelegate (Person);

class CellInfo 

     public string Title get; set;
     public string FormatString get; set;
     public EvalExpressionDelegate EvalExpression = null;


fields.Add("FirstName", new CellInfo 
                   
                      Title = "First Name", 
                      FormatString = "Foo",
                      EvalExpression = p => p.FirstName
                   );

【讨论】:

+1 好信息。我猜Func&lt;Person, string&gt; 是您所拥有的代表的简写,而有人没有意识到这一点并给了您一票否决。 @ProfessorChaos 我认为否决票可能是因为写出委托被认为是老式的做法,尽管它可以有其优点,例如命名参数。【参考方案4】:

(你的问题很清楚但很长。修剪最初的东西。)

这就是 ASP.NET MVC 使用反射和 lambda 表达式在 html 输入等上创建字段名称的方式。所以你可以看看源代码。

简单来说,您必须将您的表达式转换为成员表达式并获取名称。简单:

MemberExpression memberExpression = EvalExpression.Body as MemberExpression;
if (memberExpression == null)
    throw new InvalidOperationException("Not a memberExpression");

if (!(memberExpression.Member is PropertyInfo))
    throw new InvalidOperationException("Not a property");

return memberExpression.Member.Name; // returns FirstName

【讨论】:

可能是第一行的命令(而不是请求)。

以上是关于lambda 表达式作为属性的主要内容,如果未能解决你的问题,请参考以下文章

Lambda 表达式怎么用?

Lambda 表达式怎么用?

Lambda 表达式怎么用?

构建动态表达式树以过滤集合属性

用不用lambda,这是一个问题

Kotlin函数 ⑥ ( 函数参数为 Lambda 表达式 | Lambda 表达式作为参数的简略写法 | 唯一参数的简略写法 | 最后一个参数的简略写法 )