Почему я могу вызвать этот метод stati c, используя имя класса, но не используя экземпляр класса? - PullRequest
0 голосов
/ 18 марта 2020
class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        p.Main(args);//instance reference error,use type name instead

        var p = new Program();
        Program.Main(args);//error disappears
    }
}

Мне кажется, я понимаю, что статика не связана с экземплярами объектов, но с чем я сталкиваюсь, так это с тем, что классы не являются синонимами объектов? Или классы не используются при создании объектов? Так почему же ошибка исчезает, когда я использую имя класса, если классы по сути являются объектами?

Я получаю, что я еще не создал экземпляр Main и не буду. Это единственное, что имеет значение? Возможно это просто не объясняется должным образом в этом классе, который я беру.

1 Ответ

6 голосов
/ 18 марта 2020

Ваша путаница очень естественна, и она усугубляется дизайном C# в этом отношении. Я постараюсь объяснить, как мы go, и я переформулирую ваши вопросы, чтобы было легче ответить:

Является ли class синонимом object?

Нет. Давайте будем очень, очень ясно по этому вопросу. «Объект» имеет спецификацию c, означающую C#. Объект всегда является экземпляром типа . В C# существует два широких вида объектов: ссылочные типы , которые копируются по ссылке , например string, и типы значений, которые копируются по значению вроде int.

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

В C# a класс определяет ссылочный тип . Экземпляры этого класса являются объектами. Сам класс не является объектом.

Обоснование этому исходит из реального мира. Класс «все объекты, которые являются газетами» сам по себе не является газетой. Класс «все люди, которые говорят по-французски» сам по себе не является французским. Это ошибка категории, которая путает описание набора вещей с конкретным c примером вещи!

(Вы можете с sh чтобы внимательно изучить дизайн прототипов языков, таких как JavaScript. В JS мы создаем специфицированный c объект, который является прототипным примером такого рода вещи, и мы создаем объект конструктора, который представляет фабрику для новых примеров такого рода вещей: прототип и конструктор работают вместе, чтобы создавать новые экземпляры, и оба являются подлинными объектами. Но опять же, ваш вопрос о C#, так что давайте сейчас придерживаться этого.)

используются ли классы при создании объектов?

Да. Мы создаем класс с new; поскольку все классы являются ссылочными типами, new создает ссылку на новый объект.

Так почему же исчезает ошибка, когда я использую имя класса, если классы по сути являются объектами?

Классы не являются объектами, но я понимаю ваше замешательство. Это, безусловно, выглядит так, как будто имя класса используется в контексте, где вы ожидаете объект. (Возможно, вам будет интересно изучить структуру таких языков, как Python, где классы являются объектами, но ваш вопрос касается C#, поэтому давайте придерживаться этого.)

Для разрешения В этой путанице нужно понимать, что оператор доступа к элементу , также называемый «оператором точки», в C# является одним из самых гибких и сложных операторов. Это делает его простым в использовании, но трудным для понимания!

Главное, что нужно понять, это то, что оператор доступа к элементу всегда имеет такую ​​форму:

  • С левой стороны от точки есть выражение, которое оценивает для вещи, которая имеет членов
  • Справа от точки находится простое имя .
  • Хотя это возможно, и обычно, для thing как объекта и thing.name как объекта, также возможно, что либо , а не является объектом, либо один или оба.

Когда вы скажем p.Main компилятор говорит: «Я знаю, что p - это экземпляр Program, и я знаю, что Main - это имя. Это имеет смысл?»

Первое, что делает компилятор, проверяет, что Program - тип p - имеет доступного члена Main, что он и делает. В этот момент разрешение перегрузки вступает во владение, и мы обнаруживаем, что единственным возможным значением Main является метод stati c. Вероятно, это ошибка , поскольку p является экземпляром, и мы пытаемся вызвать stati c через экземпляр. Дизайнеры C# могли это допустить - это разрешено на других языках. Но так как это вероятная ошибка, они запретили это.

Когда вы набираете Program.Main, Program не является объектом . Компилятор проверяет, что Program ссылается на тип, а типы имеют члены . Еще раз, разрешение перегрузки вступает во владение, и это определяет, что единственный возможный смысл - то, что Main вызывается. Так как Main is stati c, а получатель - вещь слева от точки - относится к типу, это разрешено.

Возможно, это просто не объясняется должным образом в я посещаю этот класс.

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

Тем не менее, если у вас есть solid гр asp по этим вопросам, вы можете начать принимать ярлыки. Как опытные C# программисты, мы говорим "p - это объект, который ...", потому что мы all знаем, что имеем в виду "p - это переменная, значение которой является ссылкой на объект, который ... "

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

Еще одна вещь, которую вы не просили но важно:

Как насчет отражения?

. NET имеет отражение систему, которая позволяет вам брать вещи, которые не объекты, такие как классы, структуры, интерфейсы, методы, свойства, события и т. д., и получение объекта, который их описывает. (Аналогия в том, что зеркальное отображение не является реальностью , но оно, безусловно, выглядит достаточно, чтобы понять реальность.)

Важно помнить, что отражающий объект не является класс . Это объект, который описывает класс. Если вы используете отражение в своей программе следующим образом:

Type t = typeof(Program);

, тогда значение t является ссылкой на объект Type, который описывает характеристики класса Program. Вы можете проверить этот объект и определить, что для метода Main было MethodInfo и так далее. Но объект не является классом . Например, вы не можете сказать

t.Main();

. Существуют способы вызывать методы через отражение, но ошибочно думать, что объект Type является , являющимся классом. Это отражает класс.

Другой вопрос, который вы не задавали, но имеет отношение к вашему образованию:

То, что вы здесь говорите, это то, что значения являются экземплярами объектов, но некоторые конструкции языка программирования, такие как классы, не являются объектами, которыми можно манипулировать как значениями. Почему некоторые конструкции языка программирования в C# являются «первым классом» - они могут рассматриваться как данные, которыми манипулирует программа, а некоторые - «вторым классом», и ими нельзя манипулировать?

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

Нам всем нужна легкая, недорогая камера, которая делает великолепные снимки, но, как говорится, у вас может быть только две. Дизайнеры C# находились в аналогичном положении:

  • Мы хотим, чтобы языки имели небольшое количество понятий, которые должны понимать новички. Более того, мы достигаем этого путем объединения разрозненных понятий в иерархии; структуры, классы, интерфейсы, делегаты и перечисления являются типами . если, в то время, foreach - это все заявления . И так далее.
  • Мы хотим иметь возможность создавать программы, которые мощно управляют значениями, важными для разработчика. Например, создание функций «первого класса» открывает новые мощные способы программирования.
  • Мы хотим, чтобы программы имели достаточно небольшую избыточность, чтобы разработчики не чувствовали, что они вынуждены проводить ненужные церемонии, но достаточную избыточность, чтобы люди могли их понять. программа как написано.

А теперь большие:

  • Мы хотим, чтобы язык был достаточно общим, чтобы позволить разработчикам бизнес-программ писать программы, которые представляют любая концепция в их бизнес-сфере
  • Мы хотим, чтобы язык был понятен для машин в такой степени, чтобы машины могли обнаружить вероятные проблемы еще до запуска программы. То есть язык должен быть статически анализируемым .

Но, как и в случае с камерой, вы не можете иметь все это сразу. C# - это язык программирования общего назначения, разработанный для программирования в целом с мощным средством проверки типа c, позволяющим находить реальные ошибки до того, как они поступят в производство. Это именно , потому что мы хотим найти тип ошибки, с которой вы сталкиваетесь, что мы делаем , а не , позволяющие рассматривать типы как первоклассные значения. Если вы относитесь к типам как к первому классу, то огромное количество возможностей анализа stati c выходит за рамки!

Другие дизайнеры языка сделали совершенно другой выбор; последствия Python высказывания «классы - это своего рода функция, а функции - это своего рода объект» резко перемещают язык к нашей желаемой цели иерархической простоты и первоклассного подхода к языковым понятиям, а также резко отстают от способности статически определить правильность Это правильный выбор для Python, но не для C#.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...