Ответ 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", уже является такой локальной; мы могли бы добавить необязательную аннотацию ко всем локалям и параметрам, чтобы заставить их действовать как "использование" переменных. Это никогда не было очень высокоприоритетной функцией, поэтому она никогда не была реализована.