0

I am stuck at the following problem:
I have a class like

public class DataItem
{
    public decimal? ValueA{ get; set; }
    public decimal? ValueB { get; set; }
    public decimal? valueC { get; set; }
    ...
}

and would like to have something like

 var keySelectors = new Dictionary<string, Func<DataItem, decimal?>>
 {
     {"ValueA", x => x.ValueA},
     {"ValueB", x => x.ValueB},
     {"ValueC", x => x.ValueC},
     ...
 }.ToList();

to be used for a user defined analysis, but I need a more generic way to create it.
So I tried the following:

var keySelectors= typeof(DataItem).GetProperties()
  .Select(x => new KeyValuePair<string, Func<DataItem, decimal?>>(x.Name, x.DoNotKnow));

the DoNotKnow is the point where I am lost.

Or is this a wrong approach for the desired result to enable the user to choose the data on which his analysis is based?

Llarian
  • 71
  • 2
  • 11
  • `y => x.GetValue(y)`? – Sweeper Feb 13 '19 at 21:01
  • Possible duplicate of [Get property value from string using reflection in C#](https://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp) – mjwills Feb 13 '19 at 21:02

3 Answers3

2

What you want to do is create a delegate to an instance method, the property's getter method. This can be done with CreateDelegate:

var props = typeof(DataItem).GetProperties()
    .Select(x => new KeyValuePair<string, Func<DataItem, decimal?>>(x.Name,
     (Func<DataItem, decimal?>)x.GetGetMethod().CreateDelegate(typeof(Func<DataItem, decimal?>))));

Invoking a delegate is faster than doing this using the reflection-based method, GetValue on PropertyInfo, but obviously the impact depends on your scenario.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • Here type of props is `IEnumerable>>`, not `Dictionary>` in the way `keySelectors` is created in the question. I mean you can not do sth like this: `props["ValueA"](dataItem)` with this answer, until you turn this `IEnumerable` of `KeyValuePair`s into a generic `Dictionary`. – Avestura Feb 15 '19 at 21:42
  • @0xaryan Yes that's all true, but it was NOT what OP did in the question. My answer keeps all the types the same. Notice how OP starts with a dictionary and turns it into a list. You wouldn't do that if what you really want is a dictionary. – Mike Zboray Feb 15 '19 at 21:56
0

Here's one way:

typeof(DataItem).GetProperties()
    .Select(p => new KeyValuePair<string, Func<DataItem, decimal?>>(
        p.Name,
        item => (decimal?)typeof(DataItem).InvokeMember(p.Name, BindingFlags.GetProperty, null, item, null)
    ));
Sergei Z
  • 535
  • 3
  • 10
0

A human readable solution:

Func<DataItem, decimal?> GetValue(PropertyInfo p) => (item) => (decimal?)(p.GetValue(item));

var keySelctors =  typeof(DataItem).GetProperties().ToDictionary(p => p.Name, GetValue);
Avestura
  • 1,438
  • 14
  • 24