views:

300

answers:

3

I am attempting to recover source from an assembly using Reg Gate's Reflector. The original source took advantage of several C# 3.0 features which has made it a little difficult to recover. For instance here is the recovered source for an anonymous type. The first thing that pops out is the <> in from on the class identifier. Run time type naming rules are apparently more liberal than design time rules. Fair enough. A simple search and replace will fix that. What other compiler manglings must I look out for and how do I deal with them?

[DebuggerDisplay(@"\{ OverrideType = {OverrideType}, EntityType = {EntityType} }", Type="<Anonymous Type>"), CompilerGenerated]
internal sealed class <>f__AnonymousType1<<OverrideType>j__TPar, <EntityType>j__TPar>
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <EntityType>j__TPar <EntityType>i__Field;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <OverrideType>j__TPar <OverrideType>i__Field;

    [DebuggerHidden]
    public <>f__AnonymousType1(<OverrideType>j__TPar OverrideType, <EntityType>j__TPar EntityType)
    {
        this.<OverrideType>i__Field = OverrideType;
        this.<EntityType>i__Field = EntityType;
    }

    [DebuggerHidden]
    public override bool Equals(object value)
    {
        var type = value as <>f__AnonymousType1<<OverrideType>j__TPar, <EntityType>j__TPar>;
        return (((type != null) && EqualityComparer<> <<OverrideType>j__TPar>.Default.Equals(this.<OverrideType>i__Field, type.<OverrideType>i__Field)) && EqualityComparer<<EntityType>j__TPar>.Default.Equals(this.<EntityType>i__Field, type.<EntityType>i__Field));
    }

    [DebuggerHidden]
    public override int GetHashCode()
    {
        int num = -338316509;
        num = (-1521134295 * num) + EqualityComparer<<OverrideType>j__TPar>.Default.GetHashCode(this.<OverrideType>i__Field);
        return ((-1521134295 * num) + EqualityComparer<<EntityType>j__TPar>.Default.GetHashCode(this.<EntityType>i__Field));
    }

    [DebuggerHidden]
    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();
        builder.Append("{ OverrideType = ");
        builder.Append(this.<OverrideType>i__Field);
        builder.Append(", EntityType = ");
        builder.Append(this.<EntityType>i__Field);
        builder.Append(" }");
        return builder.ToString();
    }

    public <EntityType>j__TPar EntityType
    {
        get
        {
            return this.<EntityType>i__Field;
        }
    }

    public <OverrideType>j__TPar OverrideType
    {
        get
        {
            return this.<OverrideType>i__Field;
        }
    }
}
+1  A: 

Lambdas that capture variables result in closures represented by similar automatically created types.

Matt Breckon
+3  A: 

The term often used for the names with <> in them are unspeakable names - because they're not valid C#. This prevents them from clashing with non-compiler-generated names, and stops you from trying to reference them in C#.

Some things which may cause them:

  • Iterator blocks generate nested types to implement them.

  • Array initializers such as:

    int[] x = new int[] { 1, 2, 3 };
    

    will generate a <PrivateImplementationDetails>{...} class. (But only for certain types.)

  • Lambda expressions may create new methods and new types to implement the logic, and static variables used to cache delegates and expression trees where possible

  • If you compile with debugging information turned on, collection and object initializers such as:

    List<string> list = new List<string> { "hello", "there" }`)
    Button button = new Button { Text = "Hi" };
    

    will cause local variables with unspeakable names to be generated. (They're used to hold the temporary value while the properties are being assigned and items being added, before the assignment to the real variable occurs.)

  • Dynamic code in C# 4 creates all kinds of weird and wonderful things

If you turn the "optimization" level up in Reflector (View / Options / Disassembler) it will normally do its best to give you something like the original source code - turn the optimization off for an interesting experience :)

Jon Skeet
Object initializers also result in an extra compiler generated variable with an *unspeakable name*
Winston Smith
@Winston: Good catch, will edit it in.
Jon Skeet
A: 

Using statements also result in a small transformation of your code, as does the Static keyword in VB.Net.

Joel Coehoorn