"правильная константа" в C#
Суть правильности const заключается в том, чтобы иметь возможность предоставлять представление экземпляра, который не может быть изменен или удален пользователем. Компилятор поддерживает это, указывая, когда вы нарушаете константность внутри константной функции или пытаетесь использовать неконстантную функцию константного объекта. Итак, не копируя подход const, есть ли методология, которую я могу использовать в C#, которая имеет те же цели?
Я знаю об неизменности, но на самом деле это не относится к объектам-контейнерам, а лишь к одному примеру.
7 ответов
Я тоже сталкивался с этой проблемой много раз и заканчивал тем, что использовал интерфейсы.
Я думаю, что важно отказаться от идеи, что C# - это любая форма или даже эволюция C++. Это два разных языка, которые имеют почти одинаковый синтаксис.
Я обычно выражаю "правильность констант" в C#, определяя представление класса только для чтения:
public interface IReadOnlyCustomer
{
String Name { get; }
int Age { get; }
}
public class Customer : IReadOnlyCustomer
{
private string m_name;
private int m_age;
public string Name
{
get { return m_name; }
set { m_name = value; }
}
public int Age
{
get { return m_age; }
set { m_age = value; }
}
}
Чтобы получить выгоду от сумасшествия (или чистоты в терминах функционального программирования), вам нужно спроектировать свои классы таким образом, чтобы они были неизменными, как и класс String в C#.
Этот подход намного лучше, чем просто пометить объект как доступный только для чтения, поскольку с неизменяемыми классами вы можете легко передавать данные в многозадачных средах.
Я просто хотел отметить, что многие из контейнеров System.Collections.Generics имеют метод AsReadOnly, который вернет вам неизменную коллекцию.
C# не имеет такой функции. Вы можете передать аргумент по значению или по ссылке. Сама ссылка неизменна, если вы не укажете модификатор ref. Но ссылочные данные не являются неизменными. Поэтому вы должны быть осторожны, если хотите избежать побочных эффектов.
MSDN:
Интерфейсы - это ответ, и на самом деле они более мощные, чем "const" в C++. const - это универсальное решение проблемы, где "const" определяется как "не устанавливает членов и не вызывает что-то, что устанавливает членов". Это хорошая условность для постоянства во многих сценариях, но не во всех. Например, рассмотрим функцию, которая вычисляет значение на основе некоторых членов, но также кэширует результаты. В C++ это считается неконстантным, хотя с точки зрения пользователя это по существу константный.
Интерфейсы дают вам больше гибкости в определении определенного подмножества возможностей, которые вы хотите предоставить в своем классе. Хотите постоянство? Просто предоставьте интерфейс без мутирующих методов. Хотите разрешить установку одних вещей, но не других? Предоставьте интерфейс только с этими методами.
Согласитесь с некоторыми другими взглядами на использование полей только для чтения, которые вы инициализируете в конструкторе, для создания неизменяемых объектов.
public class Customer
{
private readonly string m_name;
private readonly int m_age;
public Customer(string name, int age)
{
m_name = name;
m_age = age;
}
public string Name
{
get { return m_name; }
}
public int Age
{
get { return m_age; }
}
}
В качестве альтернативы вы также можете добавить область доступа к свойствам, то есть public get и protected set?
public class Customer
{
private string m_name;
private int m_age;
protected Customer()
{}
public Customer(string name, int age)
{
m_name = name;
m_age = age;
}
public string Name
{
get { return m_name; }
protected set { m_name = value; }
}
public int Age
{
get { return m_age; }
protected set { m_age = value; }
}
}
- Ключевое слово const может использоваться для констант времени компиляции, таких как примитивные типы и строки
- Ключевое слово readonly может использоваться для констант времени выполнения, таких как ссылочные типы
Проблема с readonly состоит в том, что она только позволяет ссылке (указателю) быть постоянной. Вещи, на которые ссылаются (указывают), все еще могут быть изменены. Это сложная часть, но нет никакого способа обойти это. Реализация постоянных объектов означает, что они не должны подвергаться изменяемым методам или свойствам, но это неудобно.
См. Также " Эффективный C#: 50 конкретных способов улучшить ваш C#" (пункт 2 - предпочитайте только чтение постоянным).