Professor Chaos
Professor Chaos

Reputation: 9060

lambda Expression as a property

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.

Upvotes: 9

Views: 4430

Answers (4)

Arjan Einbu
Arjan Einbu

Reputation: 13672

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

Upvotes: 3

Jan
Jan

Reputation: 16032

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

Upvotes: 2

Tadeusz
Tadeusz

Reputation: 6883

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

Upvotes: 0

Aliostad
Aliostad

Reputation: 81660

(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

Upvotes: -1

Related Questions