.Net-detective: about interfaces and reflection

    Recently, I was interested in the structure of such an ancient .Net interface as IList. Why I was interested in this is a separate long story, of which I, probably. I'll tell you next time.

    To study this interface in more detail, I first decided to see what methods it declares. Using reflection:

     foreach(var tp in typeof(IList).GetMembers())
           Console.WriteLine(tp.Name);
    

    ... I got the following results:
    get_Item
    set_Item
    Add
    Contains
    Clear
    get_IsReadOnly
    get_IsFixedSize
    IndexOf
    Insert
    Remove
    RemoveAt
    Item
    IsReadOnly
    IsFixedSize
    

    As you can easily guess, the prefixes indicate the getter and setter of the interface properties, that is, with us. besides all methods, there are three more properties: Item with the ability to write and read, and two reodonly properties IsReadOnly and IsFixedSize. In addition, obscure duplication of names is noticeable: get_IsReadOnly // IsReadOnly, get_IsFixedSize // IsFixedSize, get_Item // set_Item // Item. In order to deal with this, I had to change the code a bit and, in addition to the class properties themselves, also print the names of the types of properties. The following code has turned out:
     foreach(var tp in typeof(IList).GetMembers())
          Console.WriteLine("{0} -- {1}", tp.Name, Enum.GetName(tp.MemberType.GetType(), tp.MemberType));
    

    This code has given me a more detailed idea. what the interface contains:
    get_Item -- Method
    set_Item -- Method
    Add -- Method
    Contains -- Method
    Clear -- Method
    get_IsReadOnly -- Method
    get_IsFixedSize -- Method
    IndexOf -- Method
    Insert -- Method
    Remove -- Method
    RemoveAt -- Method
    Item -- Property
    IsReadOnly -- Property
    IsFixedSize -- Property
    

    So, it became clear that get_IsReadOnly is a getter method of the IsReadOnly property (which is a separate member of the interface, along with the method), just like get_IsFixedSize is a method called when the IsFixedSize property is read. The Item property here has both a setter and a getter, that is, it can be accessed as if reading it. and changing.
    Realizing this, I immediately wondered: what will happen if the methods for the properties are already predefined.
    Having quickly cooked up the first example, I became convinced. that such code will not compile:
        public class Test1
        {
            public int A { get; set; }
            public int get_A()
            {
                return 0;
            }
        }
    

    The compiler produces the following error:
    Type 'TestArray.Test1' already reserves a member called 'get_A' with the same parameter types	
    

    The second property of Item turned out to be more interesting. My hunch that an indexer is hiding behind a property with the same name turned out to be true and I was able to cook up a second uncompiled class, this time with an indexer:
        public class Test2
        {
            public int Item { get; set; }
            public int this[int num]
            {
                get
                {
                    return 0;
                }
            }
        }
    

    This time the error description was slightly different, but the essence of the problem was also clear:
    The type 'TestArray.Test2' already contains a definition for 'Item'	
    

    However, reverse attempts to “trick” the compiler by explicitly implementing the methods required by the indexer were unsuccessful. The following two class examples compiled without problems,

        public class Test4
        {
            public int Item { get; set; }
        }
        public class Test3
        {
            public Test3 get_Item(int index)
            {
                return this;
            }
            public void set_Item(int index, Test3 value)
            {
            }
        }
    

    However, an attempt to access class instances using an indexer led to a compilation error:
    Cannot apply indexing with [] to an expression of type 'TestArray.Test4'	
    

    Thus. the compiler checks for the syntax of the indexer at compile time, which prevents us from using such a tricky way to determine our own indexer.

    The following conclusions can be drawn from a small investigation:
    • The C # compiler uses a fairly simple and obvious algorithm to generate the names of internal methods when using syntactically “sugar” constructs such as indexer and property setter / getter.
    • Even without inventing complex names for your methods, you can get a problem with name collisions, which will not be so easy to understand without knowing the details of the .Net internal device.
    • The Item property and its corresponding setters and getters are converted by compilers to the syntax of the postfix operator “square brackets” (= indexer), which is the syntactic sugar for the get_Item () construct.


    If the article is pleasant. then in the next article I will tell you what I was interested in the IList interface.

    Also popular now: