С# - что означает "деструкторы не наследуются"?

В разделе 10.13 "Деструкторы" С# Language Specification 3.0 указано следующее:

Деструкторы не наследуются. Таким образом, класс не имеет деструкторов, отличных от того, который может быть объявлен в этом классе.

Раздел Деструкторы Руководство по программированию на С# содержит пример, демонстрирующий, как вызываются деструкторы в иерархии наследования, включая следующую инструкцию:

... деструкторы для... классов вызываются автоматически и, по порядку, из самого полученного к наименее производному.

Я исследовал это с помощью различных практических примеров, в том числе с базовым классом, который определяет деструктор, с производным классом, который наследуется от базового класса и не определяет деструктор. Создание экземпляра производного класса, позволяющего исключить все ссылки на экземпляр из области видимости, а затем принудительное удаление мусора, показывает, что деструктор, определенный в базовом классе, вызывается, когда экземпляр производного класса завершен.

Мой вопрос заключается в том, что "деструкторы не наследуются" на самом деле означает, поскольку, хотя вы не можете явно вызвать деструктор, деструкторы в цепочке наследования вызываются автоматически, а деструкторы базового класса вызывают, даже если производные класс не определяет деструктор?

Связано ли это с каким-то тонким смысловым различием, что финализация выполняется сборщиком мусора, а не языком С#/компилятором?

Изменить 1:

В то время как спецификация языка С# также заявляет, что "конструкторы экземпляров не наследуются", поведение по отношению к конструкторам существенно отличается от дескрипторов и подходит лучше ИМО с "ненасыщенной" терминологией, как показано в примере ниже:

  public class ConstructorTestBase
  {
    public ConstructorTestBase(string exampleParam)
    {
    }
  }

  public class ConstructorTest: ConstructorTestBase
  {
    public ConstructorTest(int testParam)
      : base(string.Empty)
    {
    }
  }

  ...

  // The following is valid since there is a derived class constructor defined that
  // accepts an integer parmameter.
  ConstructorTest test1 = new ConstructorTest(5);

  // The following is not valid since the base class constructor is not inherited
  // by the derived class and the derived class does not define a constructor that
  // takes a string parameter.
  ConstructorTest test2 = new ConstructorTest("Test"); 

Поведение по отношению к деструкторам сильно отличается от поведения, как показано в следующем примере, который расширяет пример предыдущего конструктора, добавляя дескриптор только к базовому классу.

  public class ConstructorTestBase
  {
    public ConstructorTestBase(string exampleParam)
    {
    }

    ~ConstructorTestBase()
    {
      Console.WriteLine("~ConstructorTestBase()");
    }
  }

  ...

  ConstructorTest test1 = new ConstructorTest(5);
  test1 = null;
  GC.Collect();

В приведенном выше примере демонстрируется, что конструкторы базового класса будут вызываться, когда экземпляр производного класса будет завершен, даже если производный класс явно не определяет деструктор.

Моя точка зрения заключается в том, что я столкнулся со многими людьми, которые не понимают и не понимают, что это происходит, и значительная часть причины этого - это выражение "деструкторы не наследуются" .

Изменить 2:

Спецификация языка С# также указывает следующее и дает пример кода реализации под капотом:

Деструкторы реализуются путем переопределения виртуального метода Finalize в System.Object. С# программам не разрешается переопределять этот метод или называть его (или его переопределения).

Поскольку реализация under-the-hood на самом деле основана на наследовании, как указано выше, я думаю, что мой вопрос верен, и я не думаю, что какие-либо из ответов, которые я получил до сих пор, рассмотрели вопрос правильно - что означает "деструкторы не наследуются" ?

Ответы

Ответ 1

Это не вопрос победы. Я стараюсь понять ваши вопросы, но вы, похоже, озабочены защитой от совершенно мнимых атак.

Оставляя это в стороне и учитывая ваши вопросы по очереди:

Мой вопрос - что такое деструкторы не наследуются "на самом деле означает, поскольку, хотя вы не можете позвонить деструктор явно, деструкторы в цепочка наследования называется автоматически, и базовый класс деструкторы вызываются, даже если производный класс не определяет деструктор?

На самом деле это означает, что деструкторы базового класса не являются членами производного класса.

Мой встречный вопрос: "Почему вы считаете, что факты, которые (1) вы не можете назвать деструктором напрямую, (2) деструкторы в цепочке наследования вызываются автоматически после сбора, и (3) деструкторы базового класса называются даже если производный класс не определяет конструктор, имеет какое-либо отношение к вопросу о том, является ли деструктор базового класса членом производного класса?

Относится ли она к некоторым тонким семантическим что окончательная доработка реализованный сборщиком мусора а не язык С#/компилятор?

Неа.

Язык С# является спецификацией; он ничего не реализует. Компилятор С# реализует спецификацию; он, конечно же, не "реализует финализацию". CLR - это то, что реализует финализацию.

Независимо от этого, тот факт, что деструкторы в базовом классе не являются членами производного класса, не имеет ничего общего с тем, как завершение выполняется сборщиком мусора CLR.

Мы вернемся к вопросу о семантике завершения CLR и почему они не имеют отношения к вопросу о наследовании в конце.

В то время как спецификация языка С# также заявляет что "конструкторы экземпляров не наследуется", поведение в отношении для конструкторов значительно отличается от дескрипторов и подходит лучше ИМО с "не унаследованным" терминология

Хорошо, я согласен с тем, что вы этому верите. Почему вы считаете, что такое поведение имеет отношение к вопросу о наследовании? Я нисколько не слежу за тем, почему вы этому верите. Что имеет отношение к наследованию, является ли рассматриваемый объект членом производного типа просто потому, что он является членом базового типа.

Я согласен, что тот факт, что конструктор базового типа не может быть вызван непосредственно через конструкцию производного типа, который не имеет этого конструктора, согласуется с тем, что конструкторы не наследуются. Я просто не понимаю, как это связано с вопросом о том, наследуются ли деструкторы.

Более серьезным фактом является то, что базовый класс с открытым безпараллельным конструктором DOES имеет этот конструктор, который вызывается, когда производный класс, который не имеет открытого конструктора без параметров, строится с его конструктором по умолчанию. Полученный класс не наследует открытый безразмерный конструктор базового класса, но он тем не менее называется. Если вы соглашаетесь с тем, что конструктор, а не наследуемый, может быть вызван таким образом, то почему бы не признать, что деструктор также вызывается с помощью подобной семантики?

Моя точка зрения заключается в том, что у меня есть столкнулись с многими людьми, которые не понять или понять, что это происходит, и значительная часть причиной этого являются "деструкторы" не наследуются ".

Я полностью согласен. Вероятно, нельзя писать деструкторы, если у вас нет четкого понимания того, что такое правильная семантика. Меня смущает количество книг для начинающих С#, которые рассматривают деструкторов как подходящую тему для новичков; написание правильного деструктора является одной из самых сложных задач на С#.

Поскольку под капотом реализация на самом деле основана на Наследование, как указано выше, я думаю мой вопрос действительно

Ваш вопрос абсолютно важен. Но теперь вы объединяете детали реализации функции со спецификацией функции.

По аналогии рассмотрим анонимные типы. Достаточно разумно, у них нет имен. Но метаданные, которые мы плеем, конечно, называет тип; CLR требует, чтобы типы имели имена. Это противоречие? На самом деле, нет. Концептуальный объект, называемый "анонимным типом" по спецификации, не имеет имени, и это важно. Конечно, разработчик может свободно использовать платформу, которая не требует именования всех типов.

Аналогично, наша реализация С# реализует деструкторы, вытесняя IL в метод, который переопределяет виртуальный метод Finalize. Язык С# был тщательно разработан, чтобы не зависеть от этой функции среды выполнения. Другая реализация С# совершенно свободна в выборе другого механизма для реализации деструкторов. (Это может быть хорошей идеей для нас, чтобы изменить спецификацию, чтобы было более ясно, что бит о том, как реализуются деструкторы, представляет собой информативную деталь реализации, а не требование языка С#.)

Но независимо от выбора деталей реализации деструкторы в базовом классе не являются членами производного класса. Так же, как и вне зависимости от деталей реализации, анонимные типы не имеют имен.

Теперь ясно, или у вас больше вопросов?