在. 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;
}
}
使用当前版本的c#,默认的Rational是0/0,这不是很酷。
在c# 4.0中,默认参数会帮助解决这个问题吗?还是会调用clr定义的默认构造函数?
琼恩·斯基特回答说:
用你的例子来说,如果有人这么做了,你希望发生什么:
Rational[]分数= new Rational[1000];
它应该遍历构造函数1000次吗?
当然应该,这就是为什么我首先写默认构造函数的原因。当没有明确定义默认构造函数时,CLR应该使用默认的归零构造函数;这样你只需要为你所使用的付费。然后,如果我想要一个包含1000个非默认Rational的容器(并且想要优化掉这1000个结构),我将使用List<Rational>而不是数组。
在我看来,这个原因还不足以阻止定义默认构造函数。
我还没有看到和后面的解等价的东西,我要给出的就是这个。
使用偏移量将值从默认0移动到您喜欢的任何值。这里必须使用属性,而不是直接访问字段。(也许在c#7的特性中,你可以更好地定义属性作用域,这样它们就不会在代码中被直接访问。)
此解决方案适用于只有值类型的简单结构(没有ref类型或可空结构)。
public struct Tempo
{
const double DefaultBpm = 120;
private double _bpm; // this field must not be modified other than with its property.
public double BeatsPerMinute
{
get => _bpm + DefaultBpm;
set => _bpm = value - DefaultBpm;
}
}
这与这个答案不同,这种方法不是特殊的套管,而是使用偏移量,这将适用于所有范围。
以枚举作为字段的示例。
public struct Difficaulty
{
Easy,
Medium,
Hard
}
public struct Level
{
const Difficaulty DefaultLevel = Difficaulty.Medium;
private Difficaulty _level; // this field must not be modified other than with its property.
public Difficaulty Difficaulty
{
get => _level + DefaultLevel;
set => _level = value - DefaultLevel;
}
}
正如我所说的,这个技巧可能不是在所有情况下都有效,即使struct只有值字段,也只有你知道它在你的情况下是否有效。只是检查。但是你知道大概的意思。
我还没有看到和后面的解等价的东西,我要给出的就是这个。
使用偏移量将值从默认0移动到您喜欢的任何值。这里必须使用属性,而不是直接访问字段。(也许在c#7的特性中,你可以更好地定义属性作用域,这样它们就不会在代码中被直接访问。)
此解决方案适用于只有值类型的简单结构(没有ref类型或可空结构)。
public struct Tempo
{
const double DefaultBpm = 120;
private double _bpm; // this field must not be modified other than with its property.
public double BeatsPerMinute
{
get => _bpm + DefaultBpm;
set => _bpm = value - DefaultBpm;
}
}
这与这个答案不同,这种方法不是特殊的套管,而是使用偏移量,这将适用于所有范围。
以枚举作为字段的示例。
public struct Difficaulty
{
Easy,
Medium,
Hard
}
public struct Level
{
const Difficaulty DefaultLevel = Difficaulty.Medium;
private Difficaulty _level; // this field must not be modified other than with its property.
public Difficaulty Difficaulty
{
get => _level + DefaultLevel;
set => _level = value - DefaultLevel;
}
}
正如我所说的,这个技巧可能不是在所有情况下都有效,即使struct只有值字段,也只有你知道它在你的情况下是否有效。只是检查。但是你知道大概的意思。