我一直想知道为什么C#在类或方法级别上不支持const
。我知道Jon Skeet长期以来一直希望支持不变性,并且我认为使用函数const的C ++语法可以帮助实现这一点。通过在类级别添加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级函数。
我不确定lambdas和代表是否会使一切都太难(或不可能)实现,但我确信有更多语言和编译器设计经验的人可以告诉我。
正如Steve B在评论中指出的那样,readonly
的存在使事情变得更复杂,因为const readonly
在runtime
期间接近相同,但readonly
在编译期间无法确定1}}值。我想我们可能有const
和readonly
级别,但这可能太混乱了?
那么,没有实现这个的原因是什么?可用性问题(理解C ++中的常量通常对新用户来说非常困难),语言设计问题(无法完成)或仅仅是优先级问题(不变性的时代 - 嗡嗡声已经结束)。?
答案 0 :(得分:24)
冒一个有点循环的解释,C#不支持const,因为CLR无论如何都不支持它。 CLR不支持它,因为它非常符合CLS。
很少有语言拥有这个概念。 C语言支持const,这在C#by readonly 关键字中得到很好的支持。但是大狗当然是C ++,它对const的适用性更广泛,毫无疑问是你正在寻找的那个。我将避免确定const应该是什么意思,这本身就是一个虫洞,只是谈论“const-ness”,即应用const的属性。
const-ness的问题在于它需要强制执行。当任意其他语言可以使用C#类并完全忽略const-ness时,这是C#中的一个问题,因为该语言不支持它。仅仅因为C#支持它而将其用于其他所有CLS语言当然是非常不切实际的。
可执行性也是C ++中的一个问题。因为该语言还支持const_cast<>。任何客户端代码都可以快速且不可抗拒地抛弃常量。你不应该,但有时你必须这样做。因为有两种常量,严格和可观察。大致类似于私人约束和公共约束。之后将 mutable 关键字添加到语言中以尝试处理对可观察常量的需求,因此至少不可避免地使用const_cast<>可以避免。有人说C ++是一门难懂的语言。不要听到C#的声音。
答案 1 :(得分:3)
你说CLR不需要改变,但是认为没有标准的方法在编译的程序集中表达这个“const” - 并且这些程序集可能不会被C#代码使用。这不是只是为C#做的事情 - 你必须为所有.NET语言做这件事。
答案 2 :(得分:2)
正如我所认为的那样,{C}与C ++相比,const
意味着不同的东西。
在C#中,您可以使用readonly
关键字来获取const
所需的功能级别。
答案 3 :(得分:2)
我曾被以下情况所鄙视:
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);
}
你的Vector.Zero3是只读的,你不能分配它,你仍然可以访问它的组件,然后发生以下愚蠢的事情:
Vector a = Vector.Zero3;
a[0] = 2.87;
现在,因为 a 只是对Vector.Vector3的引用,后者也有Vector.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;
}
...
}
这个hack保证永远不会修改你的静态只读变量。
答案 4 :(得分:1)
如果您提出了const-class,请说:
这样的类只能在构造时填充,所以我们需要一个构造函数来接受一个int
但是,无论如何,通过将所有属性设为只读,您已经实现了所说的内容。
我不能代表C#语言设计师,但也许没有const
应用于许多其他结构的原因是因为添加它根本不值得努力,你可以用其他方式绕过这个问题(如上所述和其他答案/评论)。
答案 5 :(得分:1)
我无法从您的问题中看出,const
关键字的重载方式将特别有用。
你的第一个例子可以合法地重写为
public class NumberContainer
{
private readonly int number;
public NumberContainer(int number)
{
this.number = number;
}
public int Number
{
get { return number; }
}
}
也许,如果编译器无法识别这个类的不变性(我不知道),某些属性可能有用吗?
在你的第二个例子中,我不明白你在驾驶什么。如果函数返回一个常量值,则可以用常量字段替换它。