【发布时间】:2010-09-24 22:22:16
【问题描述】:
在 .NET 中,值类型 (C# struct) 不能有没有参数的构造函数。根据this post,这是 CLI 规范强制要求的。会发生什么情况是,对于每个值类型,都会创建一个默认构造函数(由编译器?),它将所有成员初始化为零(或 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,这不是很酷。
PS:对于 C# 4.0,默认参数会帮助解决这个问题,还是会调用 CLR 定义的默认构造函数?
Jon Skeet 回答:
以您的示例为例,当有人这样做时,您希望发生什么:
Rational[] fractions = new Rational[1000];它应该通过你的构造函数运行 1000 次吗?
当然应该,这就是我首先编写默认构造函数的原因。当未定义显式默认构造函数时,CLR 应使用 默认归零 构造函数;这样你只需为你使用的东西付费。然后,如果我想要一个包含 1000 个非默认 Rationals 的容器(并且想要优化掉 1000 个结构),我将使用 List<Rational> 而不是数组。
在我看来,这个原因不足以阻止定义默认构造函数。
【问题讨论】:
-
+1曾经遇到过类似的问题,终于把struct转成class了。
-
C#4 中的默认参数无济于事,因为
Rational()调用的是无参数ctor 而不是Rational(long num=0, long denom=1)。 -
请注意,在 Visual Studio 2015 附带的 C# 6.0 中,将允许为结构编写零参数实例构造函数。所以
new Rational()将调用构造函数,如果它存在,但如果它不存在,new Rational()将等价于default(Rational)。在任何情况下,当您想要结构的“零值”(对于您建议的Rational设计而言,这是一个“坏”数字)时,我们鼓励您使用语法default(Rational)。值类型T的默认值始终为default(T)。所以new Rational[1000]永远不会调用结构构造函数。 -
为了解决这个具体问题,你可以在结构体中存储
denominator - 1,这样默认值就变成了0/1 -
Then if I want a container of 1000 non-default Rationals (and want to optimize away the 1000 constructions) I will use a List<Rational> rather than an array.为什么你希望一个数组为一个结构体调用一个不同的构造函数到一个 List?