Где находятся только для чтения / const в .NET? - PullRequest
30 голосов
/ 12 мая 2010

В C ++ вы увидите void func(const T& t) везде.Тем не менее, я не видел ничего подобного в .NET.Почему?

Я заметил большое количество параметров, использующих struct.Но я не вижу функций с readonly / const.Фактически теперь, когда я попробовал это, я не мог использовать эти ключевые слова для создания функции, которая обещает не изменять передаваемый список. Нет ли способа пообещать вызывающей стороне, что эта функция никогда не изменит содержимое списка?Нет ли способа сказать, чтобы позвонить код и сказать, что этот список никогда не должен быть изменен?(Я знаю, что могу клонировать список или посмотреть документацию, но иногда мне нравятся ошибки компиляции)

Ответы [ 5 ]

44 голосов
/ 12 мая 2010

Неизменяемость по-прежнему остается областью, где C # созревает. До сих пор C # не принял семантику const C ++ ... что, на самом деле, я считаю хорошей вещью. Поведение const в C ++ часто затрудняло проектирование иерархий классов, которые работали бы так, как вы хотели. Нередко можно было увидеть код с const_cast<> для обхода константности там, где это было нежелательно. Надеемся, что разработчики C # придумают более простую, но все же выразительную альтернативу.

В настоящее время не существует языковой функции, которая помечает параметры или объекты, передаваемые в методы, как неизменяемые. Лучшее, что вы можете сделать, - передать объект, используя интерфейс (или, что еще лучше, оболочку), который только разрешает операции чтения.

Для некоторых стандартных коллекций в .NET вы можете использовать оболочку ReadOnlyCollection, которая инкапсулирует любой изменяемый тип ICollection в контейнере только для чтения.

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

private readonly int[] m_Values = new int[100];

public void SomeMethod()
{
    m_Values = new int[50]; // illegal, won't compile!
    m_Values[10] = 42;      // perfectly legal, yet undesirable
}

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

Практика, которую я нашел полезной при разработке неизменяемых типов, заключается в разделении неизменяемого поведения на собственный интерфейс , который затем реализуется классом, который управляет данными. Интерфейс предоставляет только те свойства и методы get, которые гарантированно не изменяют состояние объекта. Затем можно передавать экземпляры вашего типа в методы в качестве параметров этого типа интерфейса. Это слабая форма поддержки неизменяемости - поскольку вызываемый метод часто может приводить ссылку на изменяемый тип . Лучшей, но более громоздкой альтернативой является создание реализации-оболочки, которая реализует тот же интерфейс и поддерживает ссылку на фактический экземпляр (так же, как ReadOnlyCollection). Это больше работы, но дает более сильную гарантию неизменности.

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

Если вам интересно больше узнать эту тему, у Эрика Липперта есть отличная серия статей об неизменяемости в C # .

7 голосов
/ 12 мая 2010

В C # отсутствует модификатор const для параметров метода. Если вы хотите иметь что-то похожее на const, вы можете использовать неизменяемые типы в своих интерфейсах. Например, метод может принять IEnumerable<T> вместо изменяемого типа коллекции. Вы также можете посмотреть на ReadOnlyCollection.

5 голосов
/ 12 мая 2010

Я заметил большое количество параметров, использующих struct.

Здесь следует упомянуть одну вещь: C # преувеличивает разницу между struct и class по сравнению с C ++, преувеличивая разницу между типами значений и ссылочными типами. В C # все классы являются ссылочными типами, а все структуры являются типами значений. В .Net по умолчанию все передается по значению.

Результатом этого различия для типов значений является то, что все типы значений копируются при передаче в функцию. Если вы передаете структуру функции, вы гарантируете, что функция не изменит вашу исходную структуру, потому что функция работает только с копией. Добавление const к такому параметру глупо.

Типы ссылок также передаются по значению. Или, более конкретно, сама ссылка передается по значению. Итак, у вас есть копия ссылки, но она указывает на один и тот же объект. Таким образом, изменения, внесенные в объект функцией, сохранятся после выхода из функции.

На поверхности, добавление опции const, по крайней мере для ссылочных типов, кажется хорошей идеей. То, где это становится немного темным, с побочными эффектами Или, скорее, как это осуществляется? Очевидно, достаточно легко сказать, что ваш код не может использовать установщики свойств. Но как насчет других методов? Любой вызов метода может потребовать изменения объекта. Даже свойство getters может иметь побочный эффект, который что-то меняет (скажем, вы реализуете функцию безопасности, чтобы заметить, когда к чему-то был последний доступ). Собираетесь ли вы запретить чтение доступ к свойству из-за побочного эффекта?

1 голос
/ 12 мая 2010

Проблема в том, что правильность констант в C / C ++ обеспечивается только компилятором. И с готовностью обошел кстати. CLR фактически обеспечивает безопасность типов в управляемом коде, а не в компиляторе. Обязательно, потому что .NET Framework поддерживает много языков. Система типов и правила взаимодействия изложены в CLI, общей языковой инфраструктуре, которая должна служить многим целям и мастерам.

Const правильность редко встречается в современных языках. Лично я знаю только C ++, язык, который не , перенесенный в CLI. Обеспечить соблюдение правил для языков, синтаксис которых далеко от них не сложен. Что-то простое, например, целочисленные типы без знака, отсутствующие в CLS, оставили заметный след в дизайне базовых сборок.

Неизменяемость (реальная, не подделанная компилятором) заставляет команды MSFT думать. Это популярно, я знаю, что команда C # думала об этом. Хорошо для параллелизма, и так далее. Эрик Липперт написал серию постов в блоге 11 , что-то вроде прекратилось. Слишком большой для одного парня и его аудитории. Если будет реальный шаг к его реализации, я верю, что они продумают и заставят его работать. Когда-нибудь. Немного языка.

0 голосов
/ 12 мая 2010

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

http://www.c -sharpcorner.com / UploadFile / bulentozkir / PassingConstInCS11082005014622AM / PassingConstInCS.aspx

...