Reliably detecting compiler generated classes in C# expression trees
Asked Answered
L

1

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.

Lizzielizzy answered 13/6, 2012 at 4:14 Comment(8)
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.Schoenfeld
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"?Lizzielizzy
Why exactly do you need this? What is the difference between the two branches in your code? Why is the difference there?Libb
Note: If using Expressions with Reflection.Emit, there will be no classes generated.Gardell
@JamesManning didn't know that, but logical. nice, thanks! :)Loutish
@Libb - 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.Lizzielizzy
@Lizzielizzy 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?Libb
@Libb 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.Lizzielizzy
S
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?

Schoenfeld answered 13/6, 2012 at 11:39 Comment(2)
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.Lizzielizzy
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.Lizzielizzy

© 2022 - 2024 — McMap. All rights reserved.