如何在结构中强制执行合同

时间:2011-11-27 18:06:45

标签: c# struct contract

我希望强制执行一个结构,使其始终对某个合同有效,由构造函数强制执行。但是,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

作为一种解决方法,我将结构更改为类,因此我可以确保在初始化新实例时始终调用构造函数。但我想知道,绝对无法获得与结构相同的行为吗?

4 个答案:

答案 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; 
    }
}