Hello. I decided to read Richter (after Shildt) and got into confusion. As far as I knew before, the interface and enum are not inherited from the object, but after such a code I am confused

IComparable F; F.ToString(); // или любой другой метод object, написал для демонстрации Console.WriteLine(typeof(IComparable).BaseType) //пустая строка 

The confusion is that, first, where did the built-in object methods come from the interface and enum ? And secondly, I have already come to terms with this, but the last line displays a blank screen instead of the name of the base class. How can this be understood, please tell me, if you consider that the interface is supposedly inherited from the object?

Then I met in his book "CLR VIA C # 4.5" page 167 (the penultimate block of the example code) the phrase in this code

 using System; internal struct Point : IComparable { private Int32 m_x, m_y; // Конструктор, просто инициализирующий поля public Point(Int32 x, Int32 y) { m_x = x; m_y = y; } // Переопределяем метод ToString, унаследованный от System.ValueType public override String ToString() { // Возвращаем Point как строку (вызов ToString предотвращает упаковку) return String.Format("({0}, {1})", m_x.ToString(), m_y.ToString()); } // Безопасная в отношении типов реализация метода CompareTo public Int32 CompareTo(Point other) { // Используем теорему Пифагора для определения точки, // наиболее удаленной от начала координат (0, 0) return Math.Sign(Math.Sqrt(m_x * m_x + m_y * m_y) - Math.Sqrt(other.m_x * other.m_x + other.m_y * other.m_y)); } // Реализация метода CompareTo интерфейса IComparable public Int32 CompareTo(Object o) { if (GetType() != o.GetType()) throw new ArgumentException("o is not a Point");    // Вызов безопасного в отношении типов метода CompareTo return CompareTo((Point)o); } } public static class Program { public static void Main() { // Создаем в стеке два экземпляра Point Point p1 = new Point(10, 10); Point p2 = new Point(20, 20); // p1 НЕ пакуется для вызова ToString (виртуальный метод) Console.WriteLine(p1.ToString()); // "(10, 10)" // p1 ПАКУЕТСЯ для вызова GetType (невиртуальный метод) Console.WriteLine(p1.GetType()); // "Point" // p1 НЕ пакуется для вызова CompareTo // p2 НЕ пакуется, потому что вызван CompareTo(Point) Console.WriteLine(p1.CompareTo(p2)); // "-1" // p1 ПАКУЕТСЯ, а ссылка размещается в c IComparable c = p1; Console.WriteLine(c.GetType()); // "Point" // p1 НЕ пакуется для вызова CompareTo // Поскольку в CompareTo не передается переменная Point, // вызывается CompareTo(Object), которому нужна ссылка // на упакованный Point // c НЕ пакуется, потому что уже ссылается на упакованный Point Console.WriteLine(p1.CompareTo(c)); // "0" // c НЕ пакуется, потому что уже ссылается на упакованный Point // p2 ПАКУЕТСЯ, потому что вызывается CompareTo(Object) Console.WriteLine(c.CompareTo(p2));// "-1" // c пакуется, а поля копируются в p2 p2 = (Point)c; // Убеждаемся, что поля скопированы в p2 Console.WriteLine(p2.ToString());// "(10, 10)" } } 

// c пакуется, а поля копируются в p2 but how can it be packaged if it refers to an already packed structure ?? After all, when an interface assigns a type to a value, then a package occurs (earlier, in the code, the interface was assigned a type of value)

    1 answer 1

    The interface is really not inherited from object. Strictly speaking, interfaces are not exactly types. This is what the specification says (clause 3.4.5):

    The interface of the interface. The members of the interface are not strictly speaking (§13.2). However, the interface is

    In other words, if the same is said in the language of Brodsky and Dostoevsky, then the interfaces are not inherited from object, but the compiler kindly allows us to use the object'a members without direct type conversion. Probably just for the sake of convenience, since in C # everything is anyway an object, and therefore has links to these methods.

    As for enum'ov, then you are wrong. They are inherited from object indirectly through System.ValueType, about which the specification also kindly informs us (§ 3.4.3):

    There are no restrictions on how you can use your system.

    As for the second part of the question about packing / unpacking, there is most likely a translation error or the book itself. In the line you are talking about, the decompression occurs (that is, the conversion of an instance of a reference type to a value type), which is easily seen by looking at the IL code. For this C # code

      Point pt = new Point(); IComparable a = pt; Point p2 = (Point) a; 

    the corresponding IL will be something like this:

     ldloca.s pt initobj MyNamespace.Point ldloc.0 box MyNamespace.Point stloc.1 ldloc.1 unbox.any MyNamespace.Point pop ret 

    as you can see, the packing operation (box) is only one, and unboxing follows

    • Thank you very much, but I almost lost faith in life. Please tell IComparable ia = new a(); object o = ia; how then to explain this line IComparable ia = new a(); object o = ia; IComparable ia = new a(); object o = ia; it just turns out that the code is compiled, and why I don’t understand, while o just refers to the same object as `IComparable ia` - Polyakov Sergey
    • one
      @polyakov_s the same specification in clause 6.1.6 tells us that implicit castes of any references to the object are possible in C # - DreamChild
    • Thank ! Very helpful to me. - Polyakov Sergey