Lambda表达式作为属性

9
我有一个工作设置,它不是强类型的,依赖于反射。
我有一个类,比如说:
class Person{

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

and

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"});

这是一个带有属性名称和一些相关信息的简单字典。 我将该字典传递给另一个模块来处理个人实例,然后执行操作。
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并获取属性值。我不知道从哪里开始或这样具有可评估属性的语法是什么。我对函数委托和表达式树还很陌生,甚至不知道要搜索哪些关键字。希望我的描述清楚;如果不清楚,请告诉我,我会提供必要的详细信息。非常感谢任何帮助。
4个回答

3

使用委托:

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);
    }
}

0

我认为你需要使用代理(delegate)。类似于这样:

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
                   });

不错的信息。我猜 Func<Person, string> 是您拥有的委托的简写,有人没有意识到这一点,给了您一个踩。 - Professor Chaos
@ProfessorChaos 我觉得负投票可能是因为写出委托被认为是老式的做法,虽然它有其优点,比如可以命名参数。 - MikeKulls

-1
这是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

它可能是第一行的命令(与请求相对)。 - MikeKulls

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接