Reputation: 9060
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
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
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
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
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