12

I'm building a C# expression-to-Javascript converter, along the lines of Linq-to-SQL, but I'm running into problems with compiler generated expression trees.

The particular problem I'm having is dealing with MemberExpression values which were compiler generated, but which DO NOT have the CompilerGeneratedAttribute specified on their types.

Here's a cut-down version of what I've been trying:

void ProcessMemberExpression(MemberExpression memberX) {
    var expression = memberX.Expression;
    var expressionType = expression.Type;
    var customAttributes = expressionType.GetCustomAttributes(true);
    var expressionTypeIsCompilerGenerated = customAttributes.Any(x => x is CompilerGeneratedAttribute);
    if (expressionTypeIsCompilerGenerated) {
        var memberExpressionValue = Expression.Lambda(memberX).Compile().DynamicInvoke();
        ... do stuff ...
    }
    else {
        ... do other stuff ...
    }
}

Now, I have a Visual Studio debugging session open and I find this (running in the Immediate Window):

expressionType.Name
"<>c__DisplayClass64"
expressionType.GetCustomAttributes(true)
{object[0]}
expressionType.GetCustomAttributes(true).Length
0

So what I have here is an obviously compiler generated class with no custom attributes and hence no CompilerGeneratedAttribute! Therefore, my code will do other stuff, when I intend it to just do stuff.

If anyone could help me out here, I'd be very grateful. If at all possible, I'd really rather not do anything sordid like matching the expressionType.Name against something like <>.*__DisplayClass.

svick
  • 236,525
  • 50
  • 385
  • 514
Rafe
  • 5,237
  • 3
  • 23
  • 26
  • 2
    Anything that has a name that's invalid C# :) The compiler intentionally uses names that aren't valid in C# but are valid in IL to ensure it won't conflict with anything in the actual source. – James Manning Jun 13 '12 at 05:47
  • Thanks, James. I'm hoping there's some less dreadful way of spotting these cases than asking "does the type name fail to match this particular regex"? – Rafe Jun 13 '12 at 06:55
  • Why exactly do you need this? What is the difference between the two branches in your code? Why is the difference there? – svick Jun 13 '12 at 10:18
  • Note: If using Expressions with Reflection.Emit, there will be no classes generated. – leppie Jun 13 '12 at 10:22
  • @JamesManning didn't know that, but logical. nice, thanks! :) – Peter Porfy Jun 13 '12 at 10:22
  • @svick - The C# compiler is, in some cases (and for reasons that escape me, as an old compiler writer), wrapping primitive constants such as true and false in these compiler-generated classes which can only be accessed via private properties. The only way to find out what is in such expressions, and thereby make a processing decision, is to evaluate them. – Rafe Jun 16 '12 at 09:52
  • @Rafe But you didn't actually address my question: why do you have to do that for compiler-generated types, but not for normal types? What is the difference between the two for you? – svick Jun 16 '12 at 13:19
  • @svick Sorry, perhaps I should have been more explicit. I am writing a C# expression-tree-to-Javascript "compiler". For example, I want the C# expression `() => x + 1 - y` to be converted to the Javascript expression `X + 1 - Y`, where X and Y are the Javascript-side names for the C# names x and y, resp. Now, sometimes the C# compiler will hide that constant `1` (well, this actually happened to me with a bool, but that's minor detail) with a generated class which I *cannot* inspect. Instead, I need to evaluate such terms and emit the JS for the resulting C# *value*, not the original expr. – Rafe Jun 18 '12 at 01:19

1 Answers1

4

Based on Jon Skeet's answer here, it sounds like checking for angle brackets will work.

Where/what is the private variable in auto-implemented property?

Community
  • 1
  • 1
James Manning
  • 13,429
  • 2
  • 40
  • 64
  • Gah, what a tragedy! Is this really how third-party Linq-to-SQL converters handle the problem? I find it amazing that they don't rigorously stick to the `CompilerGeneratedAttribute` approach. Oh, well - thanks for the link, Skeet is usually right on the money. – Rafe Jun 13 '12 at 11:52
  • Thanks for the pointer, although I haven't yet found the answer to my question in Matt's code. What I meant to say earlier was that I can't believe *Microsoft* don't stick rigorously to using their `CompilerGeneratedAttribute`. Most frustrating. – Rafe Jun 14 '12 at 00:55