1

I have had to find a way to substitute implicit field references in a lambda expression with it's real value. For example :

Expression<Func<TestObject, String>> exp = null;
for (int i = 0; i < 1; i++)
{
    exp = t => t.SubObjs[i].TestSTR;
}
Func<TestObject, String> testFunc = exp.Compile();
String testValue = testFunc(myObj);

When inspecting the delegate, you can see this :

{t => t.SubObjs.get_Item(value(testExpression.Program+<>c__DisplayClass4).i).TestSTR}

When calling the delegate outside the for loop, the value of "i" is solved, by reference. But "i" have changed since it's last iteration ("i" == 1 and not 0).

So I build a specific ExpressionVisitor in order to replace the corresponding node with a ConstantExpression :

public class ExpressionParameterSolver : ExpressionVisitor
{
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.ToString().StartsWith("value(") && node.NodeType == ExpressionType.MemberAccess)
        {
            var index = Expression.Lambda(node).Compile().DynamicInvoke(null);
            return Expression.Constant(index, index.GetType());
        }
        return base.VisitMember(node);
    }
}

I don't have found a way other than .StartsWith("value(") in order to detect that the current node is a reference to a field... this kind of node inherits from FieldExpression but this class is internal, and I'm not sure FieldExpression only encapsulate what I consider an "implicit field reference".

So is there a way (an attribute or a method) to explicitly know that a MemberExpression node is an implicit field reference ???

Thanks in advance !!!

and thanks to this stakx post

Community
  • 1
  • 1
rducom
  • 7,072
  • 1
  • 25
  • 39
  • Value of "i" is the only problem? Then you may simply use a local variable to make your things work easily. – Akash Kava Jul 09 '11 at 15:45
  • I'm not the only one using this code, and unfortunately I can't force developers using my library to make local variables in their loops... – rducom Jul 09 '11 at 16:01
  • Thats right, but I think then your developers should do it right, if you allow them to override default behavior of c#, will not make them confused that even if its wrong way of coding, your library makes it right, they will be confused for code that does not use your library. – Akash Kava Jul 09 '11 at 16:03
  • @Akash you are right. I'm trying to bypass a default c# behavior, in order to simplify the way of declaring lambda in loops. – rducom Jul 09 '11 at 16:19

1 Answers1

4

Just fetch the Member property from the expression and see whether it's a FieldInfo...

If you only want it to be for cases where the class is compiler-generated you could use

if (expression.Member is FieldInfo && 
    expression.Member
              .DeclaringType
              .IsDefined(typeof(CompilerGeneratedAttribute), false))
{
    ....
}

There can be other reasons why a type might be compiler-generated though. It doesn't sound like a terribly good idea to me.

Can't you just avoid capturing loop variables in your lambda expressions to start with?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • If I write t => t.id, and if id is a field, the node.Member is also a FieldInfo. This solution is not appropriate : what I want to find, is that the node is an implicit reference to a field, and not a field itself. It's really the "value(testExpression.Program+<>c__DisplayClass4).i" Expression part that I want to detect. – rducom Jul 09 '11 at 15:40
  • @Raph: Well, as far as the expression is concerned, they're both just fields. You could check whether the field is a member of a compiler-generated class, I suppose... – Jon Skeet Jul 09 '11 at 15:44
  • No, I intend to use the lib I'm building with exactly this kind of lambda... And you are really right : the problem is to make the difference between implicit and explicit compiler-generated parameters... ... – rducom Jul 09 '11 at 15:56
  • @Raph: Given that the lambda expression really does represent capturing the iteration variable, I would just state it as a natural side-effect. It would be much better not to get into this situation than to try to work around it, IMO. – Jon Skeet Jul 09 '11 at 16:00
  • I use theses lambdas to extract explicit delegates to any object properties and I need to map sub properties (as in a list 4 ex), in order to map them to the getter and setter of a dynamically build type. I know it is a pretty strange approach, but I don't have choice. I have to handle properties inside indexed ones... – rducom Jul 09 '11 at 16:11