Подтвердить что ты не робот

Где readonly/const в .NET?

В С++ вы увидите void func(const T& t) всюду. Однако я не видел ничего подобного в .NET. Почему?

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

4b9b3361

Ответ 1

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

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

Для некоторой стандартной коллекции .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). Это больше работает, но обеспечивает более надежную гарантию неизменности.

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

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

Ответ 2

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

Ответ 3

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

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

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

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

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

Ответ 4

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

Исправлена ​​некорректность на текущих языках. Лично я знаю только С++, язык, который не переносится в CLI. Принудительно применять правила для языков, которые не имеют синтаксиса для них. Что-то простое, как неподписанные интегральные типы, не находящиеся в CLS, оставило заметную метку в дизайне базовых сборок.

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