/// <summary> /// Selects all elements of a `IEnumerable` property for validation. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <typeparam name="TItem">The type of an individual item in the `IEnumerable` property.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="selector"> /// The property selector expression. /// <para> /// The expression must be a `MemberExpression` (e.g. `x => x.Property`) or a `ParameterExpression` /// to select all elements of the current value (e.g. `x => x`). /// </para> /// </param> /// <param name="action">The action to perform for each item of the selected `IEnumerable` property.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> ForEach <T, TItem>(this IValidatorContext <T> validator, Expression <Func <T, IEnumerable <TItem> > > selector, Action <IValidatorContext <TItem> > action) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); ValidationInternals.ValidateNotNull(selector, nameof(selector)); ValidationInternals.ValidateNotNull(action, nameof(action)); var name = (selector.Body is ParameterExpression) ? null : ValidationInternals.GetPropertyName(selector); var value = selector.Compile().Invoke(validator.Value); if (value is null) { return(validator); } int i = 0; foreach (var item in value) { var context = (name is null) ? new ValidatorContext <TItem>(item, $"{ValidationInternals.FormatName(validator.Path, null)}[{i++}]") : new ValidatorContext <TItem>(item, validator.Path, $"{name}[{i++}]"); action.Invoke(context); } return(validator); }
/// <summary> /// Throws if the current value is `null` or empty (contains the default value of the current type). /// <para> /// This validation as well applies to empty strings or `IEnumerable` types without at least one element. /// </para> /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> NotNullOrEmpty <T>(this IValidatorContext <T> validator) where T : class { ValidationInternals.ValidateNotNull(validator, nameof(validator)); try { validator.NotNull(); } catch (ArgumentNullException) { throw new ArgumentNullException(validator.Path.First(), string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeNullOrEmpty, ValidationInternals.FormatName(validator.Path, null))); } var isEmptyEnum = (validator.Value is IEnumerable enumerable) && !enumerable.GetEnumerator().MoveNext(); var isEmptyString = validator.Value is string { Length : 0 }; if (isEmptyEnum || isEmptyString) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeNullOrEmpty, ValidationInternals.FormatName(validator.Path, null)), validator.Path.First()); } return(validator); }
/// <summary> /// Throws if the current value is equal to the blacklisted value. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="value">The blacklisted value.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> NotEqual <T>(this IValidatorContext <T> validator, T value) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (EqualityComparer <T> .Default.Equals(validator.Value, value)) { throw new ArgumentNullException(validator.Path.First(), string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeValue, ValidationInternals.FormatName(validator.Path, null), value)); } return(validator); }
/// <inheritdoc cref="NotNull{T}(ZySharp.Validation.IValidatorContext{T})"/> public static IValidatorContext <T?> NotNull <T>(this IValidatorContext <T?> validator) where T : struct { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (!validator.Value.HasValue) { throw new ArgumentNullException(validator.Path.First(), string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeNull, ValidationInternals.FormatName(validator.Path, null))); } return(validator); }
/// <summary> /// Performs validations after projecting the current value to a new type. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <typeparam name="TNew">The type of the projected value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="selector">The selector lambda.</param> /// <param name="action">The action to perform with the projected value.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> Select <T, TNew>(this IValidatorContext <T> validator, Func <T, TNew> selector, Action <IValidatorContext <TNew> > action) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); ValidationInternals.ValidateNotNull(selector, nameof(selector)); ValidationInternals.ValidateNotNull(action, nameof(action)); var context = new ValidatorContext <TNew>(selector.Invoke(validator.Value), validator.Path, null); action.Invoke(context); return(validator); }
/// <summary> /// Throws if the uri does not contain an absolute uri. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> Absolute <T>(this IValidatorContext <T> validator) where T : Uri { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (!validator.Value.IsAbsoluteUri) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.UriMustBeAbsolute, ValidationInternals.FormatName(validator.Path, null)), validator.Path.First()); } return(validator); }
/// <summary> /// Throws if the stream is not seekable. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> Seekable <T>(this IValidatorContext <T> validator) where T : Stream { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (!validator.Value.CanSeek) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.StreamMustBeSeekable, ValidationInternals.FormatName(validator.Path, null)), validator.Path.First()); } return(validator); }
/// <summary> /// Throws if the current value is not less than or equal to the given threshold. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="threshold">The threshold value.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> LessThanOrEqualTo <T>(this IValidatorContext <T> validator, T threshold) where T : struct, IComparable <T> { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (validator.Value.CompareTo(threshold) > 0) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustBeGreaterThan, ValidationInternals.FormatName(validator.Path, null), threshold), validator.Path.First()); } return(validator); }
/// <summary> /// Throws if the current value is empty (contains the default value of the current type). /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> NotEmpty <T>(this IValidatorContext <T> validator) where T : struct { ValidationInternals.ValidateNotNull(validator, nameof(validator)); if (validator.Value.Equals(default(T))) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeEmpty, ValidationInternals.FormatName(validator.Path, null)), validator.Path.First()); } return(validator); }
/// <summary> /// Performs validations if a user-defined condition is met. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="predicate">The filter predicate.</param> /// <param name="action">The action to perform if the condition is met.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> When <T>(this IValidatorContext <T> validator, Func <T, bool> predicate, Action <IValidatorContext <T> > action) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); ValidationInternals.ValidateNotNull(predicate, nameof(predicate)); ValidationInternals.ValidateNotNull(action, nameof(action)); if (predicate(validator.Value)) { action.Invoke(validator); } return(validator); }
/// <summary> /// Throws if the current value is equal to one of the blacklisted values. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="values">The blacklisted values.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> NotEqual <T>(this IValidatorContext <T> validator, params T[] values) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); var isValidValue = values.All(x => !EqualityComparer <T> .Default.Equals(validator.Value, x)); if (!isValidValue) { throw new ArgumentNullException(validator.Path.First(), string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustNotBeOneOf, ValidationInternals.FormatName(validator.Path, null), string.Join(", ", values.Select(x => $"'{x}'").ToList()))); } return(validator); }
/// <summary> /// Selects a property for validation. /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <typeparam name="TNext">The type of the selected property.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="selector"> /// The property selector expression. /// <para> /// The expression must be a `MemberExpression` (e.g. `x => x.Property`). /// </para> /// </param> /// <param name="action">The action to perform for the selected property.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> For <T, TNext>(this IValidatorContext <T> validator, Expression <Func <T, TNext> > selector, Action <IValidatorContext <TNext> > action) { ValidationInternals.ValidateNotNull(validator, nameof(validator)); ValidationInternals.ValidateNotNull(selector, nameof(selector)); ValidationInternals.ValidateNotNull(action, nameof(action)); var name = ValidationInternals.GetPropertyName(selector); var value = selector.Compile().Invoke(validator.Value); var context = new ValidatorContext <TNext>(value, validator.Path, name); action.Invoke(context); return(validator); }
/// <summary> /// Throws if the current value is not in the given range. /// <para> /// This range check is "inclusive" which means that the lower- and upper- limits are both valid values. /// </para> /// </summary> /// <typeparam name="T">The type of the current value.</typeparam> /// <param name="validator">The current validator context.</param> /// <param name="min">The minimum allowed value.</param> /// <param name="max">The maximum allowed value.</param> /// <returns>The unmodified validator context.</returns> public static IValidatorContext <T> InRange <T>(this IValidatorContext <T> validator, T min, T max) where T : struct, IComparable <T> { ValidationInternals.ValidateNotNull(validator, nameof(validator)); try { validator.GreaterThanOrEqualTo(min); validator.LessThanOrEqualTo(max); } catch (ArgumentException e) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustBeInRange, ValidationInternals.FormatName(validator.Path, null), min, max), validator.Path.First(), e); } return(validator); }
/// <summary> /// Selects an argument for validation. /// </summary> /// <typeparam name="T">The type of the argument.</typeparam> /// <param name="value">The value of the argument to validate.</param> /// <param name="name">The name of the argument to validate.</param> /// <returns>A validator context for the given argument.</returns> public static IValidatorContext <T> For <T>([ValidatedNotNull][NoEnumeration] T value, string name) { ValidationInternals.ValidateNotNull(name, nameof(name)); return(new ValidatorContext <T>(value, name)); }