Problem decompiling IEnumerable related code

4 posts, 0 answers
  1. Rodrigo
    Rodrigo avatar
    2 posts
    Member since:
    Mar 2016

    Posted 10 May Link to this post

    Hi,

     

    I'm using JustDecompile to decompile a DLL for educational purposes, and I get the following method:

     

    private IEnumerable<BaseComponent> method_21(Type type_0)
    {
          DatabaseReader.Class103 variable = new DatabaseReader.Class103(-2)
          {
              databaseReader_0 = this,
              type_1 = type_0
          };
          return variable;
    }

     

    The problem is that the DatabaseReader doesn't have an inner class called Class103. When you click on it to navigate, it doesn't do anything, it doesn't exist in the left treeview. I'm getting this error in several places in this class. In every place this happens on a method that returns IEnumerable or IEnumerable<T>.

    Does anyone know how could I patch this, even manually in code?

  2. Alexander
    Admin
    Alexander avatar
    80 posts

    Posted 11 May Link to this post

    Hi Rodrigo,

    From what I can see from the code, that you have sent to us, I suspect that this assembly is obfuscated. Please, keep in mind that this is not a supported scenario in JustDecompile. If this is the case you can try using the de4dot deobfuscator plugin for JustDecompile. It's not guaranteed to fix everything, but it's the best attempt in this case.

    If the assembly is not obfuscated then you can try by showing the compiler generated types and members. You can do that by going to Tools -> Settings and checking the "Show compiler generated types and members" checkbox. After that you need to restart JustDecompile, in order changes to take effect.

    If none of the above work you can zip the assembly where that happens and send it over to my email - alexander.dimitrov [at] telerik.com. I will take a look at it. Please, note that [at] must be replaced with @.


    Regards,
    Alexander
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. DevCraft banner
  4. Rodrigo
    Rodrigo avatar
    2 posts
    Member since:
    Mar 2016

    Posted 20 May Link to this post

    Hi Alexander,

     

    Thank you so much, that did the trick. Now I can navigate to those classes.They're all Enumerator classes.

    Do know what kind of code would generate such compiler generated classes?

    Here's one example, just for information:

    [CompilerGenerated]
    private sealed class Class108<T> : IDisposable, IEnumerable<T>, IEnumerator<T>, IEnumerable, IEnumerator
    where T : PersistentObject
    {
        private T gparam_0;
     
        private int int_0;
     
        private int int_1;
     
        public DatabaseReader databaseReader_0;
     
        public string string_0;
     
        public string string_1;
     
        public DatabaseReader.CreatorDelegate<T> creatorDelegate_0;
     
        public DatabaseReader.CreatorDelegate<T> creatorDelegate_1;
     
        public Guid guid_0;
     
        public Guid guid_1;
     
        public Guid guid_2;
     
        public Guid guid_3;
     
        public IEnumerable<T> ienumerable_0;
     
        public T gparam_1;
     
        public IEnumerator<T> ienumerator_0;
     
        T System.Collections.Generic.IEnumerator<T>.Current
        {
            [DebuggerHidden]
            get
            {
                return this.gparam_0;
            }
        }
     
        object System.Collections.IEnumerator.Current
        {
            [DebuggerHidden]
            get
            {
                return this.gparam_0;
            }
        }
     
        [DebuggerHidden]
        public Class108(int int_2)
        {
            this.int_0 = int_2;
            this.int_1 = Thread.CurrentThread.ManagedThreadId;
        }
     
        private void method_0()
        {
            this.int_0 = -1;
            if (this.ienumerator_0 != null)
            {
                this.ienumerator_0.Dispose();
            }
        }
     
        [DebuggerHidden]
        IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
        {
            DatabaseReader.Class108<T> variable;
            if (Thread.CurrentThread.ManagedThreadId != this.int_1 || this.int_0 != -2)
            {
                variable = new DatabaseReader.Class108<T>(0)
                {
                    databaseReader_0 = this.databaseReader_0
                };
            }
            else
            {
                this.int_0 = 0;
                variable = this;
            }
            variable.string_0 = this.string_1;
            variable.creatorDelegate_0 = this.creatorDelegate_1;
            variable.guid_0 = this.guid_1;
            variable.guid_2 = this.guid_3;
            return variable;
        }
     
        [DebuggerHidden]
        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.System.Collections.Generic.IEnumerable<T>.GetEnumerator();
        }
     
        bool System.Collections.IEnumerator.MoveNext()
        {
            bool flag;
            try
            {
                switch (this.int_0)
                {
                    case 0:
                    {
                        this.int_0 = -1;
                        this.ienumerable_0 = this.databaseReader_0.ReadRelated<T>(this.string_0, this.creatorDelegate_0, this.guid_0, this.guid_2);
                        if (this.ienumerable_0 == null)
                        {
                            goto Label0;
                        }
                        this.ienumerator_0 = this.ienumerable_0.GetEnumerator();
                        this.int_0 = 1;
                        break;
                    }
                    case 2:
                    {
                        this.int_0 = 1;
                        break;
                    }
                    default:
                    {
                        goto Label0;
                    }
                }
                while (this.ienumerator_0.MoveNext())
                {
                    this.gparam_1 = this.ienumerator_0.Current;
                    if (this.gparam_1 == null)
                    {
                        continue;
                    }
                    if (this.gparam_1.IsPersistent)
                    {
                        this.gparam_0 = this.gparam_1;
                        this.int_0 = 2;
                        flag = true;
                        return flag;
                    }
                    else
                    {
                        this.databaseReader_0.ilog_0.WarnFormat("ReadPersistentRelated: Ignoring non-persistent object: {0}", this.gparam_1);
                    }
                }
                this.method_0();
            Label0:
                flag = false;
            }
            return flag;
        }
     
        [DebuggerHidden]
        void System.Collections.IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }
     
        void System.IDisposable.Dispose()
        {
            switch (this.int_0)
            {
                case 1:
                case 2:
                {
                    try
                    {
                    }
                    finally
                    {
                        this.method_0();
                    }
                    return;
                }
                default:
                {
                    return;
                }
            }
        }
    }

  5. Alexander
    Admin
    Alexander avatar
    80 posts

    Posted 30 May Link to this post

    Hi Rodrigo,

    First of all, please, excuse me for the huge delay.

    This kind of compiler generated classes are generated by the C# compiler for yield statements. For example, this simple method:
    IEnumerable<T> SimpleMethodWithYield<T>(int a)
    {
        if (a == 1)
        {
             yield return default(T);
        }
    }

    generates this code:
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
     
    namespace SimpleYield
    {
        public class Class1
        {
            public Class1()
            {
            }
     
            private IEnumerable<T> SimpleMethodWithYield<T>(int a)
            {
                return new Class1.u003cSimpleMethodWithYieldu003ed__0<T>(-2)
                {
                    u003cu003e4__this = this,
                    u003cu003e3__a = a
                };
            }
     
            [CompilerGenerated]
            // <SimpleMethodWithYield>d__0
            private sealed class u003cSimpleMethodWithYieldu003ed__0<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IDisposable, IEnumerator
            {
                // <>1__state
                private int u003cu003e1__state;
     
                // <>2__current
                private T u003cu003e2__current;
     
                // <>l__initialThreadId
                private int u003cu003el__initialThreadId;
     
                private int a;
     
                // <>3__a
                public int u003cu003e3__a;
     
                // <>4__this
                public Class1 u003cu003e4__this;
     
                T System.Collections.Generic.IEnumerator<T>.Current
                {
                    [DebuggerHidden]
                    get
                    {
                        return this.u003cu003e2__current;
                    }
                }
     
                object System.Collections.IEnumerator.Current
                {
                    [DebuggerHidden]
                    get
                    {
                        return this.u003cu003e2__current;
                    }
                }
     
                [DebuggerHidden]
                public u003cSimpleMethodWithYieldu003ed__0(int u003cu003e1__state)
                {
                    this.u003cu003e1__state = u003cu003e1__state;
                    this.u003cu003el__initialThreadId = Environment.CurrentManagedThreadId;
                }
     
                bool MoveNext()
                {
                    int u003cu003e1_state = this.u003cu003e1__state;
                    if (u003cu003e1_state == 0)
                    {
                        this.u003cu003e1__state = -1;
                        if (this.a == 1)
                        {
                            this.u003cu003e2__current = default(T);
                            this.u003cu003e1__state = 1;
                            return true;
                        }
                    }
                    else
                    {
                        if (u003cu003e1_state != 1)
                        {
                            return false;
                        }
                        this.u003cu003e1__state = -1;
                    }
                    return false;
                }
     
                [DebuggerHidden]
                IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
                {
                    Class1.u003cSimpleMethodWithYieldu003ed__0<T> variable;
                    if (this.u003cu003e1__state != -2 || this.u003cu003el__initialThreadId != Environment.CurrentManagedThreadId)
                    {
                        variable = new Class1.u003cSimpleMethodWithYieldu003ed__0<T>(0)
                        {
                            u003cu003e4__this = this.u003cu003e4__this
                        };
                    }
                    else
                    {
                        this.u003cu003e1__state = 0;
                        variable = this;
                    }
                    variable.a = this.u003cu003e3__a;
                    return variable;
                }
     
                [DebuggerHidden]
                IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return this.System.Collections.Generic.IEnumerable<T>.GetEnumerator();
                }
     
                [DebuggerHidden]
                void System.Collections.IEnumerator.Reset()
                {
                    throw new NotSupportedException();
                }
     
                [DebuggerHidden]
                void System.IDisposable.Dispose()
                {
                }
            }
        }
    }

    As you see, there is obviously a bug when decompiling generic methods with yield in them. We will add this to our backlog.

    Regards,
    Alexander
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top