我希望强制执行一个结构,使其始终对某个合同有效,由构造函数强制执行。但是,default
运营商违反了合同。
考虑以下内容,例如:
struct NonNullInteger
{
private readonly int _value;
public int Value
{
get { return _value; }
}
public NonNullInteger(int value)
{
if (value == 0)
{
throw new ArgumentOutOfRangeException("value");
}
_value = value;
}
}
// Somewhere else:
var i = new NonNullInteger(0); // Will throw, contract respected
var j = default(NonNullInteger); // Will not throw, contract broken
作为一种解决方法,我将结构更改为类,因此我可以确保在初始化新实例时始终调用构造函数。但我想知道,绝对无法获得与结构相同的行为吗?
答案 0 :(得分:6)
我不知道你怎么能这样做,因为,与一个班级不同,a struct always has a default parameterless constructor;给定结构的编写方式,不能阻止值为0:
结构不能包含显式无参数构造函数。结构 成员会自动初始化为默认值。
答案 1 :(得分:3)
一种方法是安排事情,使默认值满足合同:
struct NonNullInteger
{
private readonly int _valueMinusOne;
public int Value
{
get { return _valueMinusOne + 1; }
}
public NonNullInteger(int value)
{
if (value == 0)
{
throw new ArgumentOutOfRangeException("value");
}
_valueMinusOne = value - 1;
}
}
答案 2 :(得分:1)
在这种情况下,优选不可变类,因为默认状态无效。就内存使用而言,它的成本要高一些,但除非您使用大量内存,否则这无关紧要。实际上,对于每种方法,在合同级别处理“非零数字”约束可能更好,而不是放入类中。
如果您确实要强制执行合同,请将异常放在Value getter而不是构造函数中。然后合同是,如果它包含0值,你将抛出异常;这里唯一真正的好处是你永远不会默默地使用零值。缺点是现在每次使用该值时都会进行比较。
答案 3 :(得分:1)
虽然你无法达到你想要的,你可以在getter中验证:
public int Value
{
get
{
if (_value == 0)
throw new InvalidOperationException("Use of uninitialized struct");
return _value;
}
}