4

If you try to use decompilers like: jetbrains dotpeek, redgate reflector, telerik justdecompile, whatever.. Sometimes if you need a code to copy or just to understand, it is not possible because are shown somethings like it:

[CompilerGenerated]
private sealed class Class15
{
    // Fields
    public Class11.Class12 CS$<>8__locals25;
    public string endName;

    // Methods
    public Class15();
    public bool <Show>b__11(object intelliListItem_0);
}

I'm not taking about obfuscation, this is happens at any time, I didsome tests (my own code), and occurs using lambdas and iterators. I'm not sure, could anyone give more information about when and why..?


So, by standard Visual Studio not compile $ and <> keywords in c# (like the code above)...
There is a way to translate or convert this decompiled code automatically?

J. Lennon
  • 3,311
  • 4
  • 33
  • 64

2 Answers2

4

Lambdas are a form of closure which is a posh way of saying it's a unit of code you can pass around like it was an object (but with access to its original context). When the compiler finds a lambda it generates a new type (Type being a class or struct) which encapsulates the code and any fields accessed by the lambda in its original context.

The problem here is, how do you generate code which will never conflict with user written code?

The compiler's answer is to generate code which is illegal in the language you are using, but legal in IL. IL is "Intermediate Language" it's the native language used by the Common Language Runtime. Any language which runs on the CLR (C#, vb.net, F#) compiles into IL. This is how you get to use VB.Net assemblies in C# code and so on.

So this is why the decompilers generate the hideous code you see. Iterators follow the exact same model as do a bunch of other language features that require generated types.

There is an interesting side effect. The Lambda may capture a variable in its original context:

public void TestCapture()
{
    StringBuilder b = new StringBuilder();
    Action l = () => b.Append("Kitties!");

}

So by capture I mean the variable b here is included in the package that defines the closure.

The compiler tries to be efficient and create as few types as possible, so you can end up with one generated class that supports all the lambdas found in a specific class, including fields for all the captured variables. In this way, if you're not careful, you can accidentally capture something you expect to be released, causing really tricky to trace memory leaks.

Ian
  • 4,885
  • 4
  • 43
  • 65
  • 2
    Good answer. As an aside, most modern decompilers are pretty good about identifying these patterns and restoring the original high level code, be it lambdas or custom iterators (`yield`). If the decompiler is configured for a C# 3+ language level and doesn't explicitly have a feature like "show compiler-generated code" enabled, seeing these artifacts could indicate an assembly was compiled with a non-Microsoft compiler or run through some kind of rewriter (e.g., for AOP purposes). Also, [this answer](http://stackoverflow.com/questions/2508828) lists many generated names emitted by csc.exe. – Mike Strobel Mar 18 '14 at 13:54
  • Yes, you know I reread what I wrote a few hours after and realised I'd actually forgotten to answer the original question, although you've added a lot of bits I didn't know :) – Ian Mar 18 '14 at 23:13
  • @Ian can you please answer the actual question? I'm actually also interested in how to do this. – David Klempfner Mar 27 '21 at 09:38
  • "how do you generate code which will never conflict with user written code?" Can you elaborate on this? I don't see why there would be an issue with user user written code? – guillefix Apr 21 '22 at 11:18
0

Is there an option to change the target framework?... I know with some decompilers they default to the lowest level framework (C# 1.0)

DawnFreeze
  • 164
  • 1
  • 3
  • 13