6

我想强制一个结构对于由构造函数强制执行的某个合同始终有效。然而,运营商违反了合同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

4 回答 4

6

我不明白你怎么能做到这一点,因为与类不同,结构总是有一个默认的无参数构造函数;鉴于您的结构的编写方式,无法防止值为 0:

结构不能包含显式的无参数构造函数。结构成员会自动初始化为其默认值。

于 2011-11-27T18:15:35.873 回答
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;
    }
}
于 2011-11-27T21:37:52.447 回答
1

在这种情况下,不可变类更可取,因为默认状态是无效的。就内存使用而言,它的成本要高一些,但这无关紧要,除非您使用大量内存。但实际上,对于每种方法,“非零数”约束可能在合同级别上更好地处理,而不是放入一个类中。

如果您真的想强制执行合同,请将异常放在 Value getter 而不是构造函数中。然后合同是,如果它确实包含 0 值,您将抛出异常;这里唯一真正的好处是你永远不会默默地使用零值。缺点是现在每次使用该值时都会进行比较。

于 2011-11-27T18:22:18.553 回答
1

虽然您无法准确实现您想要的,但您可以在 getter 中验证:

public int Value
{
    get 
    { 
        if (_value == 0) 
            throw new InvalidOperationException("Use of uninitialized struct"); 
        return _value; 
    }
}
于 2011-11-27T18:34:20.413 回答