Почему в С# не разрешены параметры const?

Это выглядит странно, особенно для разработчиков на С++. В С++ мы использовали для обозначения параметра const, чтобы убедиться, что его состояние не будет изменено в методе. Существуют также другие специфические причины С++, такие как передача const ref для передачи по ref и убедитесь, что состояние не будет изменено. Но почему мы не можем пометить как параметры метода const в С#?

Почему я не могу объявить свой метод следующим образом?

    ....
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....

Ответ 1

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

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

Если const действительно сделал это, это было бы здорово. Констант этого не делает. Константа - это ложь!

Const не предоставляет никаких гарантий, которые я действительно могу использовать. Предположим, у вас есть метод, который принимает const. Существует два автора кода: человек, который пишет вызывающего абонента и человека, напиравшего вызываемого. Автор вызываемого лица сделал метод взятием const. Что могут предположить два автора, является инвариантным относительно объекта?

Ничего. Вызов может отбрасывать const и мутировать объект, поэтому у вызывающего нет гарантии, что вызов метода, который принимает константу, фактически не будет мутировать его. Аналогично, вызываемый не может предположить, что содержимое объекта не будет меняться во время действия вызываемого абонента; вызываемый может вызвать некоторый мутирующий метод для non const псевдонима объекта const, и теперь так называемый const-объект изменился.

C-style const не гарантирует, что объект не изменится и поэтому будет нарушен. Теперь у C уже есть система слабого типа, в которой вы можете сделать переинтерпрет при двойном в int, если вы действительно этого хотите, поэтому не должно быть неожиданностью, что он имеет систему слабого типа по отношению к const. Но С# был разработан так, чтобы иметь хорошую систему типов, систему типов, где, когда вы говорите "эта переменная содержит строку", эта переменная фактически содержит ссылку на строку (или null). Мы абсолютно не хотим вводить модификатор "const" C-типа в систему типов, потому что мы не хотим, чтобы система типов была ложью. Мы хотим, чтобы система типов была сильной, чтобы вы могли правильно рассуждать о своем коде.

Const в C является ориентиром; это в основном означает "вы можете доверять мне, чтобы не пытаться мутировать эту вещь". Это не должно быть в системе типов; материал в системе типов должен быть фактом об объекте, о котором вы можете рассуждать, а не о его правиле.

Теперь, не пойми меня неправильно; просто потому, что const в C глубоко нарушен, не означает, что вся концепция бесполезна. То, что я хотел бы увидеть, - это действительно правильная и полезная форма аннотации "const" в С#, аннотация, которую могут использовать как люди, так и компиляторы, чтобы помочь им понять код и что среда выполнения может использовать для таких операций, как автоматическая паралеллизация и другие продвинутые оптимизации.

Например, представьте, можете ли вы "нарисовать прямоугольник" вокруг куска кода и сказать: "Я гарантирую, что этот кусок кода не выполняет никаких мутаций в любое поле этого класса" таким образом, который мог бы быть проверен компилятором, Или нарисуйте поле, в котором говорится, что "этот чистый метод изменяет внутреннее состояние объекта, но никак не может наблюдаться вне поля". Такой объект не может быть безопасно многопоточным автоматически, но он может быть автоматически сохранен в памяти. Есть всевозможные интересные аннотации, которые мы могли бы наложить на код, который обеспечил бы богатую оптимизацию и более глубокое понимание. Мы можем сделать гораздо лучше, чем слабая аннотация для const-стиля.

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

Теперь, если вы хотите всего лишь аннотацию к локальной переменной, которая является параметром, который говорит, что "значение этого параметра не изменяется во всем методе", тогда, конечно, это было бы легко сделать. Мы могли бы поддерживать "readonly" locals и параметры, которые были бы инициализированы один раз, и ошибка времени компиляции для изменения метода. Переменная, объявленная оператором "using", уже является такой локальной; мы могли бы добавить необязательную аннотацию ко всем локалям и параметрам, чтобы заставить их действовать как "использование" переменных. Это никогда не было очень высокоприоритетной функцией, поэтому она никогда не была реализована.

Ответ 2

Одна из причин, по которой в С# нет const correctness, потому что она не существует на уровне выполнения. Помните, что у С# 1.0 не было никаких функций, если это не было частью среды выполнения.

И несколько причин, почему CLR не имеет понятия корректности const, например:

  • Это усложняет время выполнения; кроме того, у JVM тоже не было этого, и CLR в основном начинался как проект для создания JVM-подобной среды исполнения, а не для С++-подобной среды исполнения.
  • Если на уровне выполнения есть константная корректность, в BCL должна быть константная корректность, в противном случае функция довольно бессмысленна в отношении .NET Framework.
  • Но если BCL требует константной корректности, каждый язык в верхней части CLR должен поддерживать константную корректность (VB, JavaScript, Python, Ruby, F # и т.д.) Это не произойдет.

Корректность Const в значительной степени является языковой функцией, присутствующей только на С++. Таким образом, это в значительной степени сводится к той же аргументации, почему CLR не требует проверенных исключений (которая является только языком Java).

Кроме того, я не думаю, что вы можете ввести такую ​​базовую функцию системы в управляемую среду, не нарушая обратной совместимости. Поэтому не рассчитывайте на постоянную корректность, когда-либо входите в мир С#.

Ответ 3

Я считаю, что есть две причины, по которым С# не const-correct.

Первое - это понятность. Немногие программисты на C++ понимают const-correctness. Простой пример const int arg симпатичен, но я также видел char * const * const arg - постоянный указатель на постоянные указатели на непостоянные символы. Констант-правильность указателей на функции - это совершенно новый уровень обфускации.

Второе - это потому, что аргументы класса - это ссылки, переданные по значению. Это означает, что уже существуют два уровня констатации, без явно понятного синтаксиса. Аналогичная точка преткновения - коллекции (и коллекции коллекций и т.д.).

Const-correctness является важной частью системы типа С++. Теоретически можно было добавить к С# как то, что проверяется только во время компиляции (его не нужно добавлять в CLR и не повлиять на BCL, если не было включено понятие методов константных членов).

Тем не менее, я считаю, что это маловероятно: вторая причина (синтаксис) будет довольно трудно решить, что сделало бы первую причину (понятность) еще более проблемой.

Ответ 4

const означает "константа времени компиляции" в С#, а не "только для чтения, но, возможно, измененная другим кодом", как в С++. Грубым аналогом С++ const в С# является readonly, но этот применим только к полям. Помимо этого, в С# вообще нет понятия С++-корректности.

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