public static Board FromBytes(byte[] source) { // The following lines represent the contracts that are checked even in release builds. // Commonly used contracts were extracted into the ContractExtensions helper class. // Note the use of the ContractArgumentValidator attribute in the helper methods. // Note that you can set the 'Emit contracts into XML doc file' project option for // code contracts. If you do so, Sandcastle will include the contract in the generated // documentation. ContractExtensions.IsNotNull(source, "source"); ContractExtensions.IsArgumentInRange(source.Length == 9 * 9, "source", "Source does not have correct size (9 * 9 = 81 elements)"); if (Contract.ForAll(source, cellValue => cellValue < 0 || cellValue > 9)) { throw new ArgumentException("Source contains invalid values"); } Contract.EndContractBlock(); var result = new Board(); try { for (byte rowIndex = 0, index = 0; rowIndex < 9; rowIndex++) { for (byte columnIndex = 0; columnIndex < 9; columnIndex++, index++) { // Store content of source[index] in a variable because it is accessed multiple times. var cellValue = source[index]; // Ignore zero if (cellValue != 0) { // Note that it is not necessary to protect board bytes because result // has just been created and nobody else has a reference on it. if (!Board.TrySetCellInternal(result.content, rowIndex, columnIndex, cellValue)) { throw new BoardException(string.Format( CultureInfo.InvariantCulture, "Specified source contains invalid value {0} in cell (row {1}, column {2})", cellValue, rowIndex, columnIndex)); } } } } } catch { // Dispose created board in case of an exception result.Dispose(); throw; } return(result); }
/// <summary> /// Tries the set the value of a cell. /// </summary> /// <param name="zeroBasedRowIndex">Index of the row.</param> /// <param name="zeroBasedColumnIndex">Index of the column.</param> /// <param name="value">The new value.</param> /// <returns><c>True</c> if the value could be set successfully, otherwise <c>false</c>.</returns> /// <remarks> /// <para> /// Note that <paramref name="value"/> must not be zero. If you want to unset a cell, /// use <see cref="ResetCell"/> instead. /// </para> /// <para> /// Note the TryXXX naming pattern. <see cref="TrySetCell"/> does the same as <see cref="SetCell"/> /// except that it does not throw an exception if the value could not be set. /// </para> /// </remarks> public bool TrySetCell(int zeroBasedRowIndex, int zeroBasedColumnIndex, byte value) { ContractExtensions.IsNotDisposed(this, this.IsDisposed); ContractExtensions.IsValidIndex(zeroBasedRowIndex, "zeroBasedRowIndex"); ContractExtensions.IsValidIndex(zeroBasedColumnIndex, "zeroBasedColumnIndex"); ContractExtensions.IsValidValue(value, "value"); Contract.EndContractBlock(); // Note that we use a write lock this time. This makes sure that only one thread // can write to the board bytes at the same time. this.contentLock.EnterWriteLock(); try { // Call internal implementation. return(Board.TrySetCellInternal(this.content, zeroBasedRowIndex, zeroBasedColumnIndex, value)); } finally { this.contentLock.ExitWriteLock(); } }