private static bool AreArgumentsValid(IReadOnlyCollection <string> arguments)
 {
     if (OperationType.IsValid(arguments.ElementAt(0)))
     {
         return(arguments.ElementAt(0) != OperationType.Print || OrderType.IsValid(arguments.ElementAt(1)));
     }
     return(false);
 }
            private static void ValidateArgs(OperationType operationType, Type entryType, object entry, int?expectedVersion)
            {
                if (!operationType.IsValid())
                {
                    throw new ArgumentException($"The argument must be one of the values defined in {typeof(OperationType).FullName}.", nameof(operationType));
                }

                if (entryType == null)
                {
                    throw new ArgumentNullException(nameof(entryType));
                }

                if (entry != null && !entryType.IsAssignableFrom(entry.GetType()))
                {
                    throw new ArgumentException($"The specified entry must be of type {entryType.FullName} or an assignable type.");
                }

                if (expectedVersion != null && expectedVersion < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(expectedVersion));
                }
            }
        public ITransactionState AddOperation(ITransactionState state, OperationType operationType, Type entryType, object entry, int?expectedVersion, out IOperation operation)
        {
            var convertedState = ToTransactionState(state);

            if (convertedState.Status != TransactionStatus.Initial)
            {
                throw new InvalidOperationException("Cannot modify a this after it has started.");
            }

            if (entryType == null)
            {
                throw new ArgumentNullException(nameof(entryType));
            }

            if (entry == null)
            {
                throw new ArgumentNullException(nameof(entry));
            }



#if DEBUG
            ValidateEntry(convertedState);
#endif

            if (!operationType.IsValid())
            {
                throw new ArgumentException($"The argument must be one of the values defined in { typeof(OperationType).FullName }.", nameof(operationType));
            }

            if (expectedVersion < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(expectedVersion));
            }

            if (entryType.IsGenericTypeDefinition)
            {
                throw new ArgumentException("The argument must not be an open generic type.", nameof(entryType));
            }

            if (!entryType.IsClass || (entryType.IsGenericType && entryType.GetGenericTypeDefinition() == typeof(Nullable <>)))
            {
                throw new ArgumentException("The argument must be a reference type.", nameof(entryType));
            }

            if (!entryType.IsAssignableFrom(entry.GetType()))
            {
                throw new ArgumentException($"The specified entry must be of a type assignale to '{nameof(entryType)}'.");
            }

            var predicate = DataPropertyHelper.CompilePredicate(entryType, entry);

            if (convertedState.Operations.Any(p => p.EntryType == entryType && predicate(p.Entry)))
            {
                throw new InvalidOperationException("The this cannot have multiple operations for a single entry.");
            }

            var operationId = GetNextOperationId(convertedState);

            var op = new Operation(convertedState.Id, operationId, operationType, entryType, entry, expectedVersion, OperationState.Unapplied);
            operation = op;

            return(new TransactionState(convertedState.Id, convertedState.Version + 1, TransactionStatus.Initial, convertedState.Operations.Add(op)));
        }