Почему C# не поддерживает const на уровне класса / метода?
мне было интересно, почему C# не поддерживает const
на уровне класса или метода. Я знаю, что Джон Скит давно хотел поддержки неизменности, и я считаю, что использование синтаксиса C++ функции const может помочь в этом. Добавив ключевое слово const на уровне класса, мы получим полную поддержку.
теперь мой вопрос в том, почему команда C# не разработала такого рода поддержку?
Я бы предположил, что все может быть создано с проверкой времени компиляции или через атрибуты, без необходимости изменения среды CLR. Я не против, чтобы код мог переопределить поведение const через отражение.
представьте себе, это:
const class NumberContainer
{
public int Number { get; }
}
.. Такой класс может быть заполнен только во время построения, поэтому нам понадобится конструктор для ввода int.
другой пример-const на уровне метода:
public int AddNumbers(NumberContainer n1, NumberContainer n2) const
{
return n1.Number + n2.Number;
}
методы уровня Const не должны иметь возможности изменять состояние самостоятельно класс или экземпляры переданных им ссылочных типов. Кроме того, функции уровня const могут вызывать только другие функции уровня const в своей области.
Я не совсем уверен, что лямбда и делегаты сделают все слишком сложным (или невозможным) для достижения, но я уверен, что кто-то с большим опытом в языке и дизайне компилятора может сказать мне.
как отметил Стив Б в комментариях, существование readonly
делает вещи немного более сложным, как const и readonly
близко к тому же во время runtime
, а readonly
значения не могут быть определены во время компиляции. Я думаю, мы могли бы const
и readonly
уровне, но это может быть слишком запутанным?
Итак, в чем причина того, что это не реализовано? Проблемы юзабилити (понимание константы в C++ обычно довольно сложно для новых пользователей), проблемы языкового дизайна (не может быть сделано) или просто приоритетные проблемы (дни неизменности-buzz закончились)..?
6 ответов
рискуя несколько круговым объяснением, C# не поддерживает const, потому что CLR не поддерживает его вообще. Среда CLR не поддерживает его, потому что она не совместима с CLS.
есть очень мало языков, которые имеют концепцию. Язык C поддерживает const, который хорошо поддерживается в C# с помощью только для чтения ключевое слово. Но большая собака, конечно, C++, который имеет гораздо более широкую применимость для const, без сомнения, тот, который вы ищете. Я избегайте определения того, что const должен означать, это червоточина сама по себе и просто говорите о "const-ness", свойстве применения const.
проблема с постоянством в том, что оно должно быть действие. Это проблема в C# , когда произвольное другое язык может использовать класс C# и полностью игнорировать const-ness только потому, что язык его не поддерживает. Закрепление его на каждом другом языке CLS только потому, что C# поддерживает его, конечно, очень непрактичный.
применимость также является проблемой в C++. Поскольку язык также поддерживает const_cast. Любой клиентский код может бросить константность прочь быстро и undiagnosably. Ты не должен, но иногда приходится. Потому что есть два вида постоянства: строгое и наблюдаемое. Примерно аналогично частной и общественной. The mutable ключевое слово было добавлено к языку позже, чтобы попытаться справиться с необходимостью наблюдаемая константа, поэтому, по крайней мере, можно избежать неизбежного использования const_cast. Некоторые говорят, что C++ - сложный язык. Не слышу этого от C#.
вы говорите, что CLR не нужно будет изменять, но учтите, что нет стандартного способа выразить эту "const"ness в скомпилированных сборках - и что эти сборки могут не использоваться кодом C# в любом случае. Это не то, что вы можете просто do для C# - вам придется сделать это для всех языков .NET.
как я считаю, что это так,const
означает разные вещи в C# по сравнению с C++.
В C# вы можете использовать readonly
ключевое слово, чтобы получить уровень функциональности вы ожидаете от const
.
однажды меня удивила следующая ситуация:
class Vector
{
private double[] m_data;
public int Dimension {get;set;}
public double this[int i]
{
get {return m_data[i];}
set {m_data[i] = value;}
}
public Vector(int n)
{
this.Dimension = n;
this.m_data = new double(n);
}
public static Vector Zero(int n)
{
Vector v = new Vector(n);
for (int i = 0; i < n; i++)
{
v[i] = 0.0;
}
return v;
}
public static readonly Vector Zero3 = Zero(3);
}
Ты Вектор.Zero3 только для чтения, и вы не можете назначить ему, вы все еще можете получить доступ к его компоненту, а затем происходит следующая глупость:
Vector a = Vector.Zero3;
a[0] = 2.87;
и теперь, начиная с a ist ничего, кроме ссылки на вектор.Vector3 последний также имеет вектор.Vector3[0] = = 2,87!
после того, как я упал в эту яму однажды, я изобрел очень простой хак, хотя и не будучи элегантным, выполняет его функция.
а именно, в класс, который я предполагаю производить статические только для чтения "константы", я ввожу логический флаг:
class Vector
{
private double[] m_data;
public int Dimension {get;set;}
private bool m_bIsConstant = false;
...
public double this[int i]
{
get {return m_data[i];}
set
{
if (!m_bIsConstant)
{
m_data[i] = value;
}
}
}
...
public static Vector Zero(int n)
{
Vector v = new Vector(n);
for (int i = 0; i < n; i++)
{
v[i] = 0.0;
}
v.m_bIsConstant = true;
return v;
}
...
}
этот хак гарантирует, что ваша статическая переменная readonly никогда не будет изменена.
в случае вашего предложения для const-класса вы говорите:
такой класс может быть заполнен только во время строительства, поэтому нам понадобится конструктор для ввода int
но, сделав все свойства доступными только для чтения, вы уже достигли того, что сказали.
Я не могу говорить за дизайнеров языка C#, но, возможно, причина не иметь const
применяется ко многим другим конструкциям, потому что добавление его просто не стоит усилие и вы можете обойти проблему другими способами (как описано выше и в других ответах/комментариях).
Я не могу сказать из вашего вопроса, как это перегрузка const
ключевое слово было бы особенно полезно.
ваш первый пример может быть переписан юридически как
public class NumberContainer
{
private readonly int number;
public NumberContainer(int number)
{
this.number = number;
}
public int Number
{
get { return number; }
}
}
возможно, если компилятор не может распознать неизменность этого класса (я не знаю), какой-то атрибут может быть полезен?