Comments
12 comments
-
The CompilerGenerated code is generated by the C# compiler if you use constructs like lambda expressions or statements such as yield return. These constructs are not implemented directly by the CLR, so the compiler has to generate extra helper code. You should be able to remove such code as it will be regenerated when the C# compiler compiles your source.
Some of the variables in such code have internal names that aren't valid as C# names.
There will be extra variables. In some cases there is metadata or information in the pdb file which allows Reflector to work out the original name of a variable, but in general it won't give you back exactly the source code you put in.
Labels and goto statements are valid within C#, so you may not need to remove them. -
But my code is refering to that CompilerGenerated Code I think. Could have been Enumerated types from what I have seen that resulted in that CompilerGenerated code.
Just to check: all local variables in methods are loosing their original names? I don't have a PDB but would Reflector use any information from the PDB while restoring code?
The label/goto statements are new. I obviously didn't have them in the original code. I guess I have to manually remove them and hope not to introduce bugs
Do you know what constructs make the compile to create label/goto statements? This info might help me during manually removing label/goto.
Thanks,
sb -
Sorry - you are completely right! Some of the CompilerGenerated code will not be needed because it corresponds to things like lambda expressions which will be regenerated in the code. However, iterator blocks will not be regenerated so you'll need to fix these up by hand, either by working out the original code or by fixing the variables inside the CompilerGenerated code to get it to compile. If you look closely at the code for the compiler generated MoveNext method then one can often figure out what it is doing.
Reflector can use the information from the PDB to get the local variable names.
WRT the goto statements, it's really the other way around. The code starts out with lots of goto statements and Reflector applies optimisations to get rid of them (you can see this original form by turning the optimisation level down). -
Here are some answers to you numbered questions:
1. [CompilerGenerated] and [DebuggerHidden] attributes are typically on things that a either generated (and you never see in Visual Studio) or in generated code (you can sometimes see the code by in other partial classes like with Forms).
The easiest way for C# to make sure you don't use these compiler generated members and objects is to name them in some illegal syntax for C# (though the names are still legal in IL - the languages have different syntax naming rules). So that is why you get those generated names that won't compile. Problem is - you won't have the information in your assembly to reverse back to things like LINQ expressions that will cause some of these objects to be created. For simple things like automatic properties (IE. public string Name { get; set; } ) you can figure those out (the underlying field name will have a generated name).
Short story is: C# provides a lot of syntatic sugar for you ... but under the coveres the compiler and visual studio work together to hide complicated generated stuff needed to make that work.
2. Local variables names are typically not stored in IL. If you have the pdb, you might be able to get them back.
3. Label_xxx: statements are examples of how the final compiled IL is not the same as the higher level language you wrote it in. Conditions and loops translate into jump or goto statements ... things you don't worry about in C#. Again this is part of the work that the C# compiler takes care of for you.
All of those items do make it harder to reverse IL into C#. #1 being the hardest (especially with LINQ and things like the yield statement). -
Thanks for all your answers!
The most annoying thing are the missing local variables. Also I have the impression the debugger added some additional local variables. As it seems just from the information contained in the assembly alone Reflector won't ever be able to restore local variables.
As for the other issues, are there any settings in the Reflector Options which will improve the results?
Will future versions of Reflector improve the restored code quality?
Thanks,
sb -
I've added a bug report (RP-809) suggesting that we allow users to turn off the output of the CompilerGenerated types (or perhaps even do this automatically). Since these have usually been hidden in regenerated C# constructs, there is really no need to have them in the output files, and at the moment they cause these compilation errors.
-
I haven't checked but isn't some of the stuff in the CompilerGenerated code sections referenced in the user code? Will leaving out the CompilerGenerated types confuse people?
Don't get me wrong I am all for leaving out the CompilerGenerated code but will it lead to compilable, bug-free code? With bug-free I mean the same runtime-behavior then the original assembly code? -
Reflector could know which CompilerGenerated classes have been subsumed by the code that was produced.
For example, if you currently export code containing an iteratorIEnumerable<int> Generate() { yield return 1; }
in Reflector 7 you will get the original iterator and a CompilerGenerated class containing the implementation of the method. This second part is not needed as it will be regenerated by the compiler from the iterator code. -
Hi, Clive, you said "in Reflector 7 you will get ...."
could you please unveil the release date please?
Thanks -
There is an EAP which was released yesterday - see Bart's post at http://www.simple-talk.com/community/blogs/bart/archive/2010/12/16/96204.aspx
-
Great
Does the early build include all the improvements or should I wait for the final 7 (I cannot test it at the moment, will soon)?
Did I trigger this new features with my post or was it planned a long time ago for version 7?
Can you shortly describe if and what kind of CompilerGenerated code is left? Or is it all gone and we now always get code back that can be directly compiled without errors?
How about Label/Goto statements? I guess you still cannot remove all of them?
Thanks! -
Hi.
The new build doesn't cover these improvements. I've logged the improvements as RP-809 and we don't know yet if the work will go into Reflector 7.
As part of the work, I intend to try to track which CompilerGenerated code has been subsumed by generated C#, but the work hasn't been done yet, so I don't know what will remain.
Label/Goto statements will be improved over time by other Reflector optimiser improvements which are not part of this work.
Add comment
Please sign in to leave a comment.
I lost the source code of an old assembly and tried to get it back. The assembly is quite tiny so I can rewrite it if recovery is not an option.
I used the 'Export...' function in Reflector so far. Some problems remain though:
1. [CompilerGenerated] and [DebuggerHidden] sections including strange variable names that won't even compile.
e.g.: private sealed class <NextCalc>d__13 : IEnumerable<...etc...
2. Also it seems local variables are renamed or additional variables added I cannot remember having in the original code.
3. There are some Label_011: and goto Label_011; commands. Can somebody how I remove or correct them without introducing bugs?
First I would like to understand why the above problems occur. Then I would obviously like to remove those problems.
Thank you.