4

I am trying to dynamically generate binary expressions using Expression.MakeBinary:

public static BinaryExpression MakeBinary(
    ExpressionType binaryType,
    Expression left,
    Expression right
)

A simple example of that for Property "Bar" of class "Foo" would be:

var param = Expression.Parameter(typeof(Foo));
var left = MemberExpression.Property(param, "Bar");
var propertyType = typeof(Foo).GetProperty("Bar").PropertyType;
var right = Expression.Constant(Convert.ChangeType("newValue", propertyType ));
var expression = Expression.MakeBinary(ExpressionType.Equal, left, right);

My goal is to be able to do the same thing as above, but instead of comparing "Bar" property with "newValue", in my case "Bar" is a dictionary and I want to compare a specific entry of that dictionary with "newValue". What I want to achieve would look like this (but this code is not valid):

var param = Expression.Parameter(typeof(Foo));
var left = MemberExpression.Property(param, "Bar[\"entryName\"]");

I would suppose what I am trying to do is possible, but I can't seem to find the right syntax/class/method to use. Obviously the code above returns an error, since Bar["entryName"] is not a property. But how can I build the expression based on a specific entry in a dictionary for a given Type?

The high level application of this is to be able to apply rules, using field/operator/compareValue as parameters, but being able to indicate the "path" to that field (depending on the class, sometimes it would be a plain property, or as asked here, an entry in a dictionary, etc.).

Thank you

roboris
  • 362
  • 2
  • 9
  • Possible duplicate of [How do I access a Dictionary Item using Linq Expressions](http://stackoverflow.com/questions/3085955/how-do-i-access-a-dictionary-item-using-linq-expressions) – Maksim Simkin Feb 03 '17 at 10:25
  • I searched, but did not realise this would provide an answer to my question. Now with René's answer I see I could have reused some components of that answer and apply it to my case. Thank you for pointing that out. The more code samples, the better :). – roboris Feb 03 '17 at 18:04
  • nevermind. Rene gave good answer and i upvoted it with pleasure :) But i knew, that this question was asked a lot of times already, so i have pointed to a duplicate. I know, it's hard to search, if you don't know exactly what are you looking for and i am not wondering, that you haven't found the answer directly – Maksim Simkin Feb 03 '17 at 18:06

1 Answers1

4

You can use Expression.MakeIndex():

var param = Expression.Parameter(typeof(Foo));
var bar = MemberExpression.Property(param, "Bar");

Type dictionaryType = typeof(Foo).GetProperty("Bar").PropertyType;
PropertyInfo indexerProp = dictionaryType.GetProperty("Item");
var dictKeyConstant = Expression.Constant("entryName");
var dictAccess = Expression.MakeIndex(bar, indexerProp, new[] {dictKeyConstant});

var propertyType = indexerProp.PropertyType;
var right = Expression.Constant(Convert.ChangeType("newValue", propertyType ));
var expression = Expression.MakeBinary(ExpressionType.Equal, dictAccess, right);    

The property name of an indexer is always "Item". The dictKeyConstant should be the expression for your dictionary's key.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • The name "Item" is correct for `Dictionary`, but it *can* be renamed in a custom class with the appropriate `IndexerNameAttribute` applied to it. Just something to be aware of if applying this elsewhere. Worth noting that VB non-default indexed properties would also be handled differently. – pinkfloydx33 Feb 03 '17 at 10:37
  • Thank you very much René, this is exactly what I was looking for. It's my first jump in C# Expressions, very different from the type of programming I usually do. Very interesting and flexible, thanks again, now I understand much better the type of approach we have to take with those Expressions, I was a bit lost at first as it is a level of abstraction higher than typical LINQ and I really was not sure how to interact with the objects from that context beyond the basics. – roboris Feb 03 '17 at 14:14
  • @roboris you're welcome. and don't worry, my brain still hurts, too. – René Vogt Feb 03 '17 at 14:16