private bool ValidateRecursive(object obj, bool throwException, int deepLevel) { const int maxDeepLevel = 100; // Prevent "StackOverflowException" (this should never happen) if (++deepLevel == maxDeepLevel) { throw new InvalidOperationException("Recursive function call exceeded the permitted deep level."); } // Validate all properties with "CommandParameterAttribute" foreach (var property in CommandParameterAttribute.GetOrderedProperties(obj)) { // If property is value type and is not nullable, than must be set to nullable if (property.PropertyType.IsValueType && Nullable.GetUnderlyingType(property.PropertyType) == null) { if (throwException) { throw new InvalidOperationException($"'{property.Name}' property must be nullable."); } return(false); } } // Validate all properties with attributes derived from "ValidationAttribute" var results = new List <ValidationResult>(); Validator.TryValidateObject(obj, new ValidationContext(obj), results, true); if (results.Count > 0) { if (throwException) { throw new ArgumentException(results[0].ToString()); } return(false); } // Find all properties value with 'CommandBuilderObjectAttribute' and validate it recursively var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var property in properties) { var propertyValue = property.GetValue(obj); if (propertyValue == null) { continue; } if (propertyValue.GetType().GetCustomAttribute <CommandBuilderObjectAttribute>() != null) { ValidateRecursive(propertyValue, throwException, deepLevel); } } return(true); }
private string BuildStringRecursive(object obj, int deepLevel) { const int maxDeepLevel = 100; // Prevent "StackOverflowException" (this should never happen) if (++deepLevel == maxDeepLevel) { throw new InvalidOperationException("Recursive function call exceeded the permitted deep level."); } var finalString = new StringBuilder(); // Loop through all properties with "CommandParameterAttribute" attribute foreach (var property in CommandParameterAttribute.GetOrderedProperties(obj)) { // Get property value var propertyValue = property.GetValue(obj); if (propertyValue == null) { continue; } // Check if property value can be included in final command string if (!CanIncludeProperty(obj, property)) { continue; } // if property value has 'CommandBuilderObjectAttribute' then build string from it recursively if (propertyValue.GetType().GetCustomAttribute <CommandBuilderObjectAttribute>() != null) { var value = BuildStringRecursive(propertyValue, deepLevel); if (!string.IsNullOrWhiteSpace(value)) { finalString.Append($" {value}"); } continue; } // Get "CommandParameterAttribute" from property var commandParameterAttribute = property.GetCustomAttribute <CommandParameterAttribute>(); if (!commandParameterAttribute.RemoveWhiteSpaceBeforeValue) { finalString.Append(" "); } var convertedPropertyValue = GetConvertedPropertyValue(obj, property); // If value format is set in "CommandParameterAttribute", then use it to format property value if (!string.IsNullOrWhiteSpace(commandParameterAttribute.Format)) { finalString.Append(string.Format(commandParameterAttribute.Format, convertedPropertyValue)); } else { finalString.Append($"{convertedPropertyValue}"); } } return(finalString.ToString().Trim()); }