Корректность констант в C # с богатыми типами

Исходя из опыта работы с C ++ и пытаясь изучить C #, одно из самых неприятных упущений языка, с которыми я столкнулся, - это эквивалент ключевого слова const.

Итак, я пытался выбрать шаблон, который можно использовать для достижения константной корректности в C #.

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

Существуют ли какие-либо шаблоны или решения, которые могут обрабатывать богатые типы и коллекции, или в C # мы вынуждены просто делать копии? Не лучше ли вообще отказаться от корректности констант в C #?


person Eric    schedule 24.07.2012    source источник
comment
Я предлагаю прочитать серию блогов «Неизменяемость в C #» Эрика Липперта. (по ссылке показаны все сообщения с тегами неизменяемости - ищите те, которые имеют заголовок Immutability in C#), где разрабатываются неизменяемые типы коллекций.   -  person Oded    schedule 25.07.2012
comment
Если вы действительно хотите, чтобы тип был неизменным, вам в значительной степени нужно разработать его как таковой. Конечно, есть ReadOnlyCollection и тому подобное, но они несколько тусклые в том, что у них все еще есть методы мутации, они просто выбрасываются при вызове. Но да, мне тоже нужна ссылка на C ++ - ish const ...   -  person James Michael Hare    schedule 25.07.2012
comment
Я программировал на C # в течение многих лет, и мне еще предстоит увидеть ни одного сценария, в котором ключевое слово const могло бы спасти меня от ошибки. Преимущества const в C ++ сильно переоценены. Вместо того, чтобы наклоняться назад, пытаясь программировать на C ++ с использованием C #, попробуйте модель C # для программирования. Сомневаюсь, что через несколько лет вы захотите вернуться.   -  person riwalk    schedule 25.07.2012
comment
@ Stargazer712: Я должен сказать, что не согласен с завышением преимуществ корректности const. Конечно, делать все правильно - это больно, но при хорошем дизайне оно того стоит. Тем не менее, я знаю многих, кто чувствует то же, что и вы, так что это всего лишь мои 0,02 доллара.   -  person James Michael Hare    schedule 25.07.2012
comment
С академической точки зрения это того стоит. На практике я еще не сталкивался с ситуацией, когда дополнительные усилия позволили бы сэкономить время или деньги.   -  person Jeff Yates    schedule 25.07.2012
comment
@JeffYates: Я бы сказал, что, вероятно, не стоит тратить усилия на модернизацию модели только для константной корректности, но если вы начнете с константно-правильного дизайна с самого начала, это может предотвратить некоторые небрежные или любительские ошибки.   -  person James Michael Hare    schedule 25.07.2012
comment
@ Stargazer712, тебе нужно const? Нет, но это определенно дает вам некоторое спокойствие и позволяет программировать способами, которые в противном случае были бы подвержены ошибкам. Вы можете свободно возвращать и передавать ссылки, а не копии, зная, что они безопасны. Я полагаю, что точный аргумент, использованный против const, может быть использован против private. Тебе действительно не нужно private (богохульство, я знаю). Но без него у вас нет гарантии инкапсуляции во время компиляции. const обеспечивает аналогичную инкапсуляцию, гарантируя, что ваши драгоценные ценности не будут изменены кем-то другим.   -  person Eric    schedule 25.07.2012
comment
Без сомнений. Однако стремление к полной константной корректности по-прежнему часто обходится дороже, чем некоторые ошибки. Здесь должен быть определенный баланс. Абсолютного здесь нет. Всегда быть константно-правильным просто смешно. Некоторым конструкциям это не нужно.   -  person Jeff Yates    schedule 25.07.2012


Ответы (1)


Можно ли добиться неизменности в C #? Конечно, если вы рассчитываете на это. Вы можете делать творческие вещи с интерфейсами и т. Д., Чтобы раскрыть только get свойств и ни один из изменяемых методов.

Тем не менее, имейте в виду, что нет ничего, что мешало бы хитрому пользователю преобразовать его обратно к фактическому типу (конечно, то же самое можно сказать и о C ++, вы можете отбросить константу).

ISomeReadOnlyInterface readOnly = new SomeFullObject();

// hah, take that read-only interface!
((SomeFullObject)readOnly).SomeMutatingMethod();

То же и с коллекциями. Даже если вы вернете ReadOnlyCollection (который предотвращает изменение поведения в самой коллекции), данные в коллекции все равно изменчивы (если, конечно, тип позволяет).

Так что, боюсь, здесь нет однозначного ответа. Не существует константы «щелчок-переключатель», которая дает вам то, что делает C ++.

Это действительно ваше дело, вы можете:

  • Создавайте неизменяемые типы и возвращайте итераторы (или другие последовательности только для чтения) вместо изменяемых коллекций.
  • Возвращайте новые копии каждый раз, чтобы не было ничего страшного, если они их переделают.
  • Просто верните фактические данные и оставьте поведение взлома как «undefined».
  • и т.д...

Последнее - то, что делают коллекции вроде Dictionary<TKey, TValue>. Нет ничего, что говорило бы, что вы не можете сделать тип ключа изменяемым типом (но горе, если вы это сделаете), и MSDN довольно ясно показывает, что если вы измените ключ таким образом, что изменится его хэш-код, он будет на вашей собственной шее. ...

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

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

person James Michael Hare    schedule 24.07.2012
comment
Отличное резюме и отличный совет - person Eric; 25.07.2012
comment
That said, keep in mind there is nothing that prevents a crafty user from casting it back to the actual type. Это смешно. Нет ничего, что мешало бы пользователю получить доступ к закрытым полям другого объекта; просто используйте отражение. Это не значит, что не должно быть private переменных. - person user; 19.09.2013
comment
@user Я вовсе не считаю это смешным. OP спрашивал, можно ли создать тип const, и ответ был непростым. Таким образом, было важно сообщить им, что, хотя это простой способ сделать это, это не гарантия. - person James Michael Hare; 19.09.2013