在.NET中,值类型(C#struct)不能具有没有参数的构造函数。根据这篇文章,这是CLI规范要求的。发生的情况是,对于每个值类型,都会创建一个默认的构造函数(由编译器生成?),它将所有成员初始化为零(或null)。
struct
null
为什么不允许定义这样的默认构造函数?
琐碎的用途是有理数:
public struct Rational { private long numerator; private long denominator; public Rational(long num, long denom) { /* Todo: Find GCD etc. */ } public Rational(long num) { numerator = num; denominator = 1; } public Rational() // This is not allowed { numerator = 0; denominator = 1; } }
使用当前版本的C#,默认的Rational 0/0不是那么酷。
0/0
PS :默认参数是否可以帮助解决C#4.0的问题,还是将调用CLR定义的默认构造函数?
乔恩·斯凯特(Jon Skeet)回答:
以您的示例为例,当某人这样做时,您希望发生什么: Rational[] fractions = new Rational[1000]; 它应该在构造函数中运行1000次吗?
以您的示例为例,当某人这样做时,您希望发生什么:
Rational[] fractions = new Rational[1000];
它应该在构造函数中运行1000次吗?
当然应该,这就是为什么我首先编写默认构造函数的原因。当未定义显式默认构造函数时,CLR应该使用 默认清零 构造函数;这样,您只需为使用的商品付费。然后,如果我想要一个1000个非默认值Rational的容器(并且想优化掉1000个结构),我将使用List<Rational>而不是一个数组。
Rational
List<Rational>
我认为,此原因不足以阻止定义默认构造函数。
注意: 下面的答案是在C#6之前写的很久的,它计划引入在结构中声明无参数构造函数的功能- 但仍然不会在所有情况下都调用它们(例如,用于数组创建) (最后此功能未添加到C#6中)。
编辑:由于Grauenwolf对CLR的了解,我已经编辑了以下答案。
CLR允许值类型具有无参数的构造函数,但C#不允许。我相信这是因为它将带来一种期望,即在不调用构造函数时会调用它。例如,考虑一下:
MyStruct[] foo = new MyStruct[1000];
仅通过分配适当的内存并将其全部清零,CLR就能非常有效地做到这一点。如果必须将MyStruct构造函数运行1000次,效率将大大降低。(事实上,它没有- 如果你 这样做 有一个参数的构造函数,当你创建一个数组没有得到执行,或者当你有一个未初始化的实例变量。)
C#中的基本规则是“任何类型的默认值都不能依赖任何初始化”。现在,他们 可以 允许定义无参数的构造函数,但随后又不需要在所有情况下都执行该构造函数- 但这会导致更多的混乱。(或者至少,所以我相信论点是正确的。)
编辑:使用您的示例,当有人这样做时,您想发生什么:
编辑:(回答了更多的问题)无参数构造函数不是由编译器创建的。就CLR而言,值类型不必具有构造函数-尽管事实证明,如果您使用IL编写它,它就 可以 。当您new Guid()在C#中编写“ ”时,将发出与调用常规构造函数时不同的IL。有关此方面的更多信息,请参见此SO问题。
new Guid()
我 怀疑 在无参数构造函数的框架中没有任何值类型。毫无疑问,NDepend可以告诉我我是否足够好……C#禁止它的事实足以让我认为这可能是一个坏主意。