lambda Expression as a property
Asked Answered
A

4

9

I have a working setup which is not strongly typed and relies on reflection.

I have a class, say

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

and I have a dictionary like this

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

It's a simple dictionary with property Names and some info about them. I pass the dictionary to another module that processes Person instances and I do

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.
       ...
    }
 }

This method of passing the string for field name and using reflection works, but I was wondering if there is a strongly-typed method of doing this.

What I had in mind was having a property that stored a linq expression, something like this

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

and during usage, somehow use the EvalExpression on a person object and get the property value. I have no clue where to begin or what the syntax would be like to have a property like this that's evaluateable. I'm new to function delegates and expression trees that I don't even know the right keywords to search for. Hope my description is clear; if not, let me know and I'll details as necessary. Any assistance would much appreciated.

Aras answered 23/9, 2011 at 10:21 Comment(0)
B
2

You can try something like this to not have to code the property names as strings if this is what you mean by saying strongly typed:

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);
    }
}
Barbette answered 23/9, 2011 at 10:37 Comment(0)
W
3

Use a delegate:

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

Then your lambda input will work...

Wahoo answered 23/9, 2011 at 10:39 Comment(0)
B
2

You can try something like this to not have to code the property names as strings if this is what you mean by saying strongly typed:

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);
    }
}
Barbette answered 23/9, 2011 at 10:37 Comment(0)
C
0

I think a delegate is what you need. Something like this:

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
                   });
Chiliad answered 23/9, 2011 at 10:36 Comment(2)
+1 Good info. I guess Func<Person, string> is a shorthand for the delegate you have and someone didn't realize that and gave you a downvote.Aras
@ProfessorChaos I think the downvote is probably because writing out the delegate is considered the old fashioned way of doing it although it can have its advantages such as naming the parameters.Froggy
D
-1

(Your question is clear but long. Trim the initial stuff.)

This is how ASP.NET MVC uses reflection and lambda expressions for creating field names on the HTML inputs, etc. So you could have a look at the source code for that matter.

In simple terms, you have to cast your expression to Member expression and get the name. Easy:

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
Declamation answered 23/9, 2011 at 10:30 Comment(1)
It could be the command (as opposed to request) on the first line.Froggy

© 2022 - 2024 — McMap. All rights reserved.