Почему в C # недопустимы константные параметры?

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

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

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

person Incognito    schedule 16.07.2010    source источник
comment
В C ++ это всегда было предохранителем, и никогда не было по-настоящему неотъемлемой частью языка, как я его видел. Разработчики C # явно не думали, что это приносит большую пользу.   -  person Noldorin    schedule 16.07.2010
comment
Более широкое обсуждение этого вопроса: правильность констант в С #: stackoverflow.com/questions/114149/const-correctness -в-с   -  person tenpn    schedule 16.07.2010
comment
Есть для типов значений [out / ref], но не для ссылочных типов. Это интересный вопрос.   -  person kenny    schedule 16.07.2010
comment
@kenny Извините, что вы имеете в виду для типов значений? У вас не может быть константных параметров независимо от типа значения или ссылочного типа   -  person Incognito    schedule 16.07.2010
comment
Как в этом вопросе могут быть теги C # и не зависящие от языка?   -  person CJ7    schedule 08.08.2010
comment
Неизменяемые данные и функции без побочных эффектов легче рассуждать. Вам может понравиться F # fsharpforfunandprofit.com/posts/is-your-language-unreasonable   -  person Colonel Panic    schedule 30.03.2019


Ответы (5)


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

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

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

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

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

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

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

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

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

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

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

person Eric Lippert    schedule 16.07.2010
comment
Извините, но я считаю этот аргумент очень слабым. Тот факт, что разработчик может солгать, нельзя предотвратить ни на одном языке. void foo (const A & a), который изменяет объект a, не отличается от int countApples (Basket b), который возвращает количество груш. Это просто ошибка, ошибка, которая компилируется на любом языке. - person Alessandro Teruzzi; 25.09.2015
comment
«Вызываемый волен отбросить константу…» ээээ… (° _ °) Это довольно поверхностный аргумент, который вы здесь приводите. Вызываемый также может просто начать записывать случайные ячейки памяти с 0xDEADBEEF. Но и то, и другое было бы очень плохим программированием, и любой современный компилятор быстро поймал бы их. В будущем при написании ответов не путайте, что технически возможно при использовании языковых бэкдоров, с тем, что возможно в реальном реальном коде. Подобная искаженная информация сбивает с толку менее опытных читателей и снижает качество информации о SO. - person Slipp D. Thompson; 04.11.2015
comment
«Const в C - это руководство»; Ссылка на источник для некоторых вещей, которые вы говорите, действительно поможет в вашем случае. В моем образовании и опыте работы в отрасли процитированное утверждение является чушью - const в C является такой же обязательной встроенной функцией, как и сама система типов - у обеих есть лазейки, чтобы обмануть их, когда это необходимо (как и все в C), но ожидается для использования книгой в 99,99% кода. - person Slipp D. Thompson; 04.11.2015
comment
@ SlippD.Thompson: Во-первых, я отмечаю, что функция, которая обеспечивает черный ход для читерства, когда это необходимо, но разработчики, как ожидается, не будут использовать, - это именно то, о чем я говорю; const в C на самом деле не дает той гарантии, которую я хотел бы использовать в этом языке. Во-вторых, я возражаю против ваших оскорблений ad hominem. В-третьих, вопрос: почему бы и нет? вопрос, который по своей сути требует мнения - мнения, которое в моем случае сформировалось в результате моего длительного сотрудничества с комитетом по дизайну C #. Наконец, я рекомендую вам написать лучший ответ или написать сообщение в блоге или что-то в этом роде, если вам не нравится мой. - person Eric Lippert; 04.11.2015
comment
Const в C ++ - эффективная и намеренно навязчивая гарантия намерения. Ваш пример лживого программиста несколько надуман. Конечно, можно было бы сделать лучше. Однако в прошлом вы писали несколько очень хороших постов. Следовательно, не могли бы вы расширить свой ответ на вопрос, как бы вы добавили корректность const в C #, если бы ваша жизнь зависела от этой функции? Или вы бы предпочли умереть? - person Patrick Fromberg; 29.08.2016
comment
Этот ответ является причиной того, почему я иногда ненавижу дизайн C #. Разработчики языка абсолютно уверены, что они намного умнее других разработчиков, и стараются чрезмерно защитить их от ошибок. Очевидно, что ключевое слово const работает только во время компиляции, потому что в C ++ у нас есть прямой доступ к памяти и мы можем делать все, что захотим, и у нас есть несколько способов обойти объявление const. Но в обычных ситуациях этого не делают. Кстати, «частный» и «защищенный» в C # также не дают никаких гарантий, поскольку мы можем получить доступ к этим методам или полям с помощью отражения. - person BlackOverlord; 30.08.2016
comment
@BlackOverlord: (1) Желание разработать язык, свойства которого естественным образом приводят разработчиков к успеху, а не к провалу, мотивировано желанием создавать полезные инструменты, а не верой в то, что дизайнеры умнее своих клиенты, как вы догадываетесь. (2) Отражение не является частью языка C #; это часть среды выполнения; доступ к отражению ограничен системой безопасности среды выполнения. Коду с низким уровнем доверия не предоставляется возможность выполнять частную рефлексию. гарантии, предоставляемые модификаторами доступа, предназначены для кода с низким уровнем доверия; Код высокого доверия может делать все, что угодно. - person Eric Lippert; 30.08.2016
comment
const C ++ не сильно сломан. Часто неправильно понимают? Да (к сожалению, возможность модификации с помощью неконстантного псевдонима, на который вы указали, все еще удивляет слишком многих программистов на C ++). Менее полезно, чем гарантия того, что указанный объект не изменится? Да, конечно. const не может устранить каждую ошибку, но это не повод отказываться от нее. - person j_random_hacker; 06.01.2017
comment
В качестве контраргумента против утверждения BlackOverlord о том, что отражение должно выдерживать критику, вы обязаны заявить, что вся серьезная разработка на C # - это код с низким уровнем доверия. (Тот факт, что гарантия конфиденциальности C # нарушена чем-то за пределами собственно языка, в то время как гарантия константности C ++ нарушена внутри языка на const_cast<T>(), является чисто академическим различием с точки зрения программиста: в конце концов, гарантия все еще нарушена.) - person j_random_hacker; 06.01.2017
comment
Вы потратили несколько дней на отслеживание ошибки в программе на c или c ++, потому что кто-то вам солгал, или откуда взялась эта бесполезная тирада? Не говорю, что я бы не забанил const_cast, если бы мог, и я действительно вижу опасность mutable, но ничто из того, что вы сказали, не дает никаких оснований, почему эта концепция не была реализована (должным образом) в C # (кроме, может быть, самого конца: Это никогда была очень приоритетной функцией). - person MikeMB; 01.06.2017
comment
это правда правда? Изменение константного объекта с помощью изменяемого представления / ссылки - это неопределенное поведение, не так ли? - person AF_cpp; 31.08.2018
comment
Этот ответ подробно иллюстрирует некоторые распространенные заблуждения о константности. Константность - это условие контракта между автором и пользователем интерфейса, так что ни одна из сторон не может случайно разорвать контракт. Вы не можете случайно отказаться от константности в современном компиляторе C ++ - вы должны стоять на голове с определенным синтаксисом. Любой, у кого есть доступ к коду, может найти любые случаи такого приведения. Правильное применение констант устраняет ошибки, которые может быть очень трудно найти, и упрощает программирование. (Это от парня, который много работал над C ++, Java и C #) - person Steve White; 20.09.2018
comment
@AF_cpp Да, это так. Извините, но этот ответ ужасен, не могу поверить, что у него так много голосов. То, что вы говорите о C, совершенно неверно. Этот ответ содержит слишком много мнений, противоречащих действительности, и не подходит для SO. - person Stargateur; 13.11.2018
comment
@Stargateur: Что ж, я призываю вас написать свой собственный ответ, который вам больше нравится. Помните, что вопрос в том, почему в C # нет const, поэтому обязательно ответьте на этот вопрос. Если вы действительно хотите написать статью, в которой объясняется, что такое константность в C, возможно, начните блог и напишите в нем свою статью. - person Eric Lippert; 13.11.2018
comment
@EricLippert Это не моя точка зрения, ваш ответ неверен с точки зрения C. Я знаю, что Microsoft в целом не любит C, это нормально, но это не позволяет вам писать неправильные вещи о C. Ответ не имеет связи со мной, я делаю свой собственный ответ. Вы просто говорите, что если вы недовольны, уходите, это очень неправильное поведение на SO, я просто комментирую, чтобы объяснить, почему я проголосовал против. Кроме того, я вижу, что в C # 7.2 есть кое-что, что теперь может вас заинтересовать, docs.microsoft.com/fr-fr/dotnet/csharp/. - person Stargateur; 13.11.2018
comment
Я не написал ничего неправильного и совсем не призываю вас уезжать. Я делаю наоборот: я призываю вас писать сообщения, которые просвещают других, чтобы ваши знания могли помочь нам всем. Я ценю ссылку на новые функции C #, но я уже знаю о них. Они иллюстрируют, как правильно и эффективно проектировать константную корректность, наблюдая за проблемами с дизайном C, которые я обнаружил восемь лет назад, когда писал этот ответ, когда у нас не было планов добавить такую ​​функцию в C #. - person Eric Lippert; 13.11.2018
comment
Тогда вы могли бы подумать о том, чтобы написать ответ на этот вопрос, который иллюстрирует, как новые функции C # 7.2 устраняют недостатки функции const в C и тем самым отвечают на заданный вопрос. К сожалению, у меня нет на это времени, но очевидно, что вы сильно относитесь к этому вопросу, поэтому я рекомендую вам потратить некоторое время на то, чтобы изложить свои мысли в виде полезного ответа. - person Eric Lippert; 13.11.2018
comment
Ответ основан на полном непонимании эталонного шаблона const C ++ и против правильной разработки программного обеспечения. Константа - очень мощный инструмент в C ++, поскольку он явно показывает разработчику, что функция делает или не делает с объектом, переданным аргументом. Это правда, что его не всегда легко использовать правильно, но это один из самых распространенных шаблонов в C ++. Он защищает разработчиков от ошибок многопоточности, помогает понять поток данных, улучшает читаемость и упрощает расширение кода. И нет, никто не преобразует константу в неконстантную. - person Tibor Takács; 24.11.2018

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

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

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

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

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

person Ruben    schedule 16.07.2010
comment
Вы уверены, что в JVM этого нет? Насколько я знаю, он есть. Вы можете попробовать public static void TestMethod (final int val) в Java. - person Incognito; 16.07.2010
comment
Final на самом деле не является константой. Вы по-прежнему можете изменять поля ссылочного IIRC, но не само значение / ссылку. (Что в любом случае передается по значению, так что это скорее уловка компилятора, которая не позволяет вам изменить значение параметра.) - person Ruben; 16.07.2010
comment
ваша 3-я пуля верна лишь отчасти. наличие константных параметров для вызовов BCL не будет критическим изменением, поскольку они просто более точно описывают контракт. Этот метод не изменит состояние объекта, в отличие от этого метода, который требует, чтобы вы передавали значение const, которое нарушало бы - person Rune FS; 16.07.2010
comment
@Rune FS: В чем тогда смысл с языковой точки зрения, если это не навязывается? Если это для целей документации, вы уже можете указать это с помощью комментария XML-документа. - person Ruben; 16.07.2010
comment
Это принудительно внутри метода, поэтому введение его в BCL не будет критическим изменением. - person Rune FS; 16.07.2010
comment
@Rune FS: то, что вы описываете, эквивалентно final Java, IIRC (только для чтения в C # для полей). В C ++ невозможно вызвать какой-либо метод для переменной / параметра const, если они не отмечены как const. Таким образом, введение константной корректности C ++ для параметров делает параметры полностью непригодными для использования, поскольку нет константных методов. (Если вы их тоже не введете, но тогда вы вернетесь ко всем языкам, которые должны поддерживать корректность const). - person Ruben; 16.07.2010
comment
Нет, я не описываю final, и вы не описываете критическое изменение, вызванное константой в параметрах, а просто заявляете, что для его введения в BCL требуется работа, и многое из этого я никогда не оспаривал. Я заявил, что это можно сделать, не нарушая клиентский код. Так же, как вы можете добавить const к аргументу в C ++, не беспокоясь об изменении всех вызывающих сайтов - person Rune FS; 16.07.2010
comment
@Rune FS: это означает, что вы можете добавлять константу только к параметрам, которые получают аргументы, которые уже являются неизменяемыми и запечатанными (в противном случае вы могли бы, например, ToString изменить материал, который он не предназначен для изменения в производном классе, нарушая правильность константы), а затем также добавьте const ко всем их методам и свойствам (иначе существующие методы не работают). Кроме того, BCL никогда не может допускать постоянные параметры незапечатанных классов. Или интерфейсы. Или делегаты. Потому что они уже неконстантные. Это сделало бы эту функцию очень ограниченной ИМХО; только для примитивов и некоторых классов, таких как строка. - person Ruben; 16.07.2010
comment
Даже если среда выполнения не может обеспечить это, было бы полезно иметь атрибут, который указывал бы, должна ли функция разрешать / ожидать запись в параметр ref (особенно, в случае методов / свойств структуры, this) . Если в методе специально указано, что он не будет записывать в параметр ref, то компилятор должен разрешить передачу значений только для чтения. И наоборот, если в методе указано, что он будет писать this, компилятор не должен разрешать вызов такого метода для значений, доступных только для чтения. - person supercat; 10.07.2013
comment
Разумеется, const - это чисто функция времени компиляции и не требует поддержки со стороны среды выполнения? Если программа, содержащая 'const', компилируется, вы можете удалить 'const' везде, где она встречается (включая библиотеки), и она все равно будет компилироваться с тем же байт-кодом. Корректность констант - это просто дополнительный уровень проверки типов, выполняемый компилятором статически. - person Ed Avis; 21.02.2017
comment
Это гораздо более удовлетворительный ответ ... разочаровывающий, но удовлетворяющий - person Assimilater; 27.06.2017

Я считаю, что есть две причины, по которым C # не является корректным с точки зрения констант.

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

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

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

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

person Stephen Cleary    schedule 16.07.2010
comment
Вы правы в том, что CLR на самом деле не нужно беспокоиться об этом, поскольку можно использовать modopt и modreq на уровне метаданных для хранения этой информации (как это уже сделано в C + / CLI - см. System.Runtime.CompilerServices.IsConst); и это может быть тривиально распространено на методы const. - person Pavel Minaev; 16.07.2010
comment
Это того стоит, но нужно делать безопасным способом. Упомянутая вами константа Deep / Shallow открывает целую банку червей. - person user1496062; 01.04.2014
comment
В C ++, где на самом деле манипулируют ссылками, я вижу ваш аргумент о наличии двух типов const. Однако в C # (где вам нужно пройти через черный ход, чтобы использовать указатели) мне кажется достаточно ясным, что существует четко определенное значение для ссылочных типов (т.е. классов) и четко определенное, хотя и другое значение для типов значений ( т.е. примитивы, структуры) - person Assimilater; 27.06.2017
comment
Программисты, не понимающие константности, не должны программировать на C ++. - person Steve White; 20.09.2018

Это возможно, начиная с C # 7.2 (декабрь 2017 г. с Visual Studio 2017 15.5).

Только для структур и базовых типов!, но не для членов классов.

Вы должны использовать in для отправки аргумента в качестве ввода по ссылке. Видеть:

См .: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier.

Для вашего примера:

....
static void TestMethod1(in MyStruct val)
{
    val = new MyStruct;  // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
    val.member = 0;  // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
    val = 0;  // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....
person isgoed    schedule 09.03.2020

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

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

person Pavel Minaev    schedule 16.07.2010
comment
Итак, вы думаете, что MS считает «шумом» постоянные параметры в методах. - person Incognito; 16.07.2010
comment
Я не уверен, что такое шум - я бы назвал это высоким соотношением цена / качество. Но, конечно, вам понадобится кто-то из команды C #, чтобы сказать вам наверняка. - person Pavel Minaev; 16.07.2010
comment
Итак, насколько я понимаю, ваш аргумент состоит в том, что константность была исключена в C # для простоты. Подумай об этом. - person Steve White; 20.09.2018