在.NET中,值类型(C#struct
)不能包含没有参数的构造函数.根据这篇文章,这是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;
}
}
Run Code Online (Sandbox Code Playgroud)
使用当前版本的C#,默认的Rational 0/0
并不是那么酷.
PS:默认参数是否有助于解决C#4.0或者是否会调用CLR定义的默认构造函数?
Jon Skeet回答道:
要使用您的示例,当有人执行时您希望发生什么:
Run Code Online (Sandbox Code Playgroud)Rational[] fractions = new Rational[1000];
它应该通过你的构造函数1000次?
当然应该,这就是我首先编写默认构造函数的原因.当没有定义显式默认构造函数时,CLR应该使用默认的归零构造函数; 这样你只需支付你使用的费用.然后,如果我想要一个1000个非默认Rational
的容器(并希望优化1000个结构),我将使用一个List<Rational>
而不是一个数组.
在我看来,这个原因并不足以阻止默认构造函数的定义.
Jon*_*eet 187
注意:下面的答案是在C#6之前很长一段时间编写的,它计划引入在结构中声明无参数构造函数的能力 - 但它们仍然不会在所有情况下被调用(例如,用于数组创建) (最后)此功能未添加到C#6).
编辑:由于格劳恩沃尔夫对CLR的洞察力,我编辑了下面的答案.
CLR允许值类型具有无参数构造函数,但C#不具有参数构造函数.我相信这是因为它会引入一种期望,即构造函数不会被调用.例如,考虑一下:
MyStruct[] foo = new MyStruct[1000];
Run Code Online (Sandbox Code Playgroud)
CLR能够通过分配适当的内存并将其归零来非常有效地完成此任务.如果它必须运行MyStruct构造函数1000次,那将效率低得多.(事实上,它没有-如果你这样做有一个参数的构造函数,当你创建一个数组它不会运行,或当你有一个未初始化的实例变量.)
C#中的基本规则是"任何类型的默认值都不能依赖于任何初始化".现在他们可以允许定义无参数构造函数,但是不需要在所有情况下执行构造函数 - 但这会导致更多的混淆.(或至少,所以我相信这个论点.)
编辑:要使用您的示例,当有人执行时您希望发生什么:
Rational[] fractions = new Rational[1000];
Run Code Online (Sandbox Code Playgroud)
它应该通过你的构造函数1000次?
编辑:(回答更多问题)无参数构造函数不是由编译器创建的.就CLR而言,值类型不必具有构造函数 - 尽管事实证明它可以在IL中编写它.当您new Guid()
在C#中写入" "时,如果您调用普通构造函数,则会发出不同的IL.有关该方面的更多信息,请参阅此SO问题.
我怀疑框架中没有无参数构造函数的任何值类型.毫无疑问NDepend可以告诉我,如果我问得好吗...... C#禁止它的事实是一个足够大的提示让我认为这可能是一个坏主意.
use*_*467 44
结构是值类型,值类型一旦声明就必须具有默认值.
MyClass m;
MyStruct m2;
Run Code Online (Sandbox Code Playgroud)
如果你声明上面的两个字段而没有实例化,那么打破调试器,m
将是null但m2
不会.鉴于此,无参数构造函数没有任何意义,实际上结构上的所有构造函数都是赋值,事物本身只是通过声明它就已存在.实际上m2可以很高兴地用在上面的例子中并调用它的方法,如果有的话,它的字段和属性被操纵!
Adi*_*iii 15
虽然CLR允许它,但C#不允许结构具有默认的无参数构造函数.原因是,对于值类型,编译器默认情况下既不生成默认构造函数,也不生成对默认构造函数的调用.因此,即使您碰巧定义了默认构造函数,也不会调用它,这只会让您感到困惑.
为避免此类问题,C#编译器不允许用户定义默认构造函数.并且因为它不生成默认构造函数,所以在定义字段时无法初始化字段.
或者最大的原因是结构是值类型,值类型由默认值初始化,构造函数用于初始化.
您不必使用new
关键字实例化您的结构.它反过来像一个int; 你可以直接访问它.
结构不能包含显式无参数构造函数.Struct成员会自动初始化为其默认值.
结构的默认(无参数)构造函数可以设置与全零状态不同的值,这将是意外行为.因此,.NET运行时禁止结构的默认构造函数.
小智 14
您可以创建一个初始化并返回默认"有理"数字的静态属性:
public static Rational One => new Rational(0, 1);
Run Code Online (Sandbox Code Playgroud)
并使用它像:
var rat = Rational.One;
Run Code Online (Sandbox Code Playgroud)
从 C# 10.0 开始,您可以:
归档时间: |
|
查看次数: |
100868 次 |
最近记录: |