How can I contract inside a structure

I would like the structure to always be valid with respect to a specific contract executed by the constructor. However, the contract is violated by the default operator.

Consider the following, for example:

 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 

As a workaround, I changed my structure to a class, so I can guarantee that the constructor is always called when the new instance is initialized. But I wonder if there is absolutely no way to get the same behavior with structure?

+6
source share
4 answers

One approach is to arrange things so that the default value satisfies the contract:

 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; } } 
+3
source

I don’t understand how you could do this, because unlike a class , a structure always has a constructor without parameters without parameters ; given how your structure is written, the value 0 cannot be prevented:

Structures cannot contain explicit constructors without parameters. Struct members are automatically initialized to default values.

+6
source

In this case, the preferred class is preferred because the default state is not valid. This is a bit more expensive than using memory, but it doesn’t matter if you do not use them very much. Indeed, although the “nonzero number” constraint is probably better handled at the contract level for each method, rather than being placed in a class.

If you really want to execute the contract, throw an exception in Getter instead of Value. Then the contract is that you will throw an exception if it ever contained the value 0; the only real advantage here is that you never use silent value. The downside is that now you have a comparison every time you use a value.

+1
source

While you cannot achieve what you want, you can check in the recipient:

 public int Value { get { if (_value == 0) throw new InvalidOperationException("Use of uninitialized struct"); return _value; } } 
+1
source

Source: https://habr.com/ru/post/902497/


All Articles