表示支持链状求值的参数值求解器,链中的每个求解器依次执行,并将求得结果作为下一个求解器的输出,最终返回最后一个求解器的结果。
Наследование: RuleParameterValueResolver
        private RuleParameter CreateConditionParameter(
            Type containerType, RuleParameterValueResolver containerResolver, string prefix, PropertyInfo property, ParamAttribute paramAttr)
        {
            var propertyType = property.PropertyType;
            var valueResolver = new ChainedRuleParameterValueResolver().Chain(containerResolver, new PropertyBackedRuleParameterValueResolver(property));
            var supportedOperators = GetDefaultOperators(propertyType);
            IRuleParameterValueSource valueSource = null;

            if (paramAttr.ValueSource != null)
            {
                valueSource = TypeActivator.CreateInstance(paramAttr.ValueSource) as IRuleParameterValueSource;
            }
            else if (property.PropertyType.IsEnum)
            {
                propertyType = typeof(String);
                valueSource = StaticRuleParameterValueSource.FromEnum(property.PropertyType);
            }
            else if (IsNullableEnum(property.PropertyType))
            {
                propertyType = typeof(String);
                valueSource = StaticRuleParameterValueSource.FromEnum(Nullable.GetUnderlyingType(property.PropertyType));
            }

            var paramName = prefix + (paramAttr.Name ?? property.Name);

            return new RuleParameter(paramName, propertyType, valueResolver, supportedOperators)
            {
                ValueSource = valueSource
            };
        }
        private RuleParameter CreateConditionParameter(
            Type containerType, RuleParameterValueResolver containerResolver, string prefix, PropertyInfo property, ParamAttribute paramAttr)
        {
            var propertyType       = property.PropertyType;
            var valueResolver      = new ChainedRuleParameterValueResolver().Chain(containerResolver, new PropertyBackedRuleParameterValueResolver(property));
            var supportedOperators = GetDefaultOperators(propertyType);
            IRuleParameterValueSource valueSource = null;

            if (paramAttr.ValueSource != null)
            {
                valueSource = TypeActivator.CreateInstance(paramAttr.ValueSource) as IRuleParameterValueSource;
            }
            else if (property.PropertyType.IsEnum)
            {
                propertyType = typeof(String);
                valueSource  = StaticRuleParameterValueSource.FromEnum(property.PropertyType);
            }
            else if (IsNullableEnum(property.PropertyType))
            {
                propertyType = typeof(String);
                valueSource  = StaticRuleParameterValueSource.FromEnum(Nullable.GetUnderlyingType(property.PropertyType));
            }

            var paramName = prefix + (paramAttr.Name ?? property.Name);

            return(new RuleParameter(paramName, propertyType, valueResolver, supportedOperators)
            {
                ValueSource = valueSource
            });
        }
        private List <RuleParameter> FindConditionParameters(Type containerType, RuleParameterValueResolver containerResolver, string prefix)
        {
            var parameters = new List <RuleParameter>();

            foreach (var property in containerType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                var refAttr = property.GetCustomAttribute <ReferenceAttribute>(false);
                if (refAttr != null)
                {
                    var resolver = new ChainedRuleParameterValueResolver().Chain(containerResolver, new PropertyBackedRuleParameterValueResolver(property));

                    var referencingType = refAttr.ReferencingType ?? property.PropertyType;
                    // Indirect reference
                    if (referencingType != property.PropertyType)
                    {
                        if (refAttr.ReferenceResolver == null)
                        {
                            throw new InvalidOperationException("Indirect reference must speicify a reference resolver. Property: " + property.ReflectedType.FullName + "." + property.Name + ".");
                        }

                        resolver.Chain(new IndirectReferenceAdapter(referencingType, refAttr.ReferenceResolver));
                    }

                    var newPrefix = prefix;

                    // refAttr.Prefix == null: Generate a default prefix
                    // refAttr.Prefix == String.Empty: Do not use prefix
                    // otherwise, use the specified prefix
                    if (refAttr.Prefix != null)
                    {
                        if (refAttr.Prefix.Length > 0)
                        {
                            newPrefix = prefix + (refAttr.Prefix.EndsWith(".") ? refAttr.Prefix : refAttr.Prefix + ".");
                        }
                    }
                    else
                    {
                        // Try to get a smart default preifx if developer doesn't specify one.
                        // If the property name is like BrandId,
                        // then we use 'Brand' instead of 'BrandId'.
                        // So when we are investigating Brand.Name property, we can get a better parameter name 'BrandName' instead of 'BrandIdName'
                        if (property.Name.EndsWith("Id"))
                        {
                            newPrefix = prefix + property.Name.Substring(0, property.Name.Length - 2);
                        }
                        else
                        {
                            newPrefix = prefix + property.Name;
                        }

                        newPrefix = newPrefix + ".";
                    }

                    parameters.AddRange(FindConditionParameters(referencingType, resolver, newPrefix));

                    // Add also extended parameters
                    foreach (var provider in Providers)
                    {
                        if (provider.GetType() != typeof(DefaultRuleParameterProvider))
                        {
                            var additionalParams = provider.GetParameters(referencingType);
                            foreach (var param in additionalParams)
                            {
                                var valueResolver = new ChainedRuleParameterValueResolver();
                                valueResolver.Chain(resolver);
                                valueResolver.Chain(param.ValueResolver);

                                var adaptedParam = new RuleParameter(newPrefix + param.Name, param.ValueType, valueResolver, param.SupportedOperators)
                                {
                                    ValueSource = param.ValueSource
                                };

                                parameters.Add(adaptedParam);
                            }
                        }
                    }
                }
                else
                {
                    var paramAttr = property.GetCustomAttribute <ParamAttribute>(false);
                    if (paramAttr != null)
                    {
                        parameters.Add(CreateConditionParameter(containerType, containerResolver, prefix, property, paramAttr));
                    }
                }
            }

            return(parameters);
        }
        private List<RuleParameter> FindConditionParameters(Type containerType, RuleParameterValueResolver containerResolver, string prefix)
        {
            var parameters = new List<RuleParameter>();

            foreach (var property in containerType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                var refAttr = property.GetCustomAttribute<ReferenceAttribute>(false);
                if (refAttr != null)
                {
                    var resolver = new ChainedRuleParameterValueResolver().Chain(containerResolver, new PropertyBackedRuleParameterValueResolver(property));

                    var referencingType = refAttr.ReferencingType ?? property.PropertyType;
                    // Indirect reference
                    if (referencingType != property.PropertyType)
                    {
                        if (refAttr.ReferenceResolver == null)
                            throw new InvalidOperationException("Indirect reference must speicify a reference resolver. Property: " + property.ReflectedType.FullName + "." + property.Name + ".");

                        resolver.Chain(new IndirectReferenceAdapter(referencingType, refAttr.ReferenceResolver));
                    }

                    var newPrefix = prefix;

                    // refAttr.Prefix == null: Generate a default prefix
                    // refAttr.Prefix == String.Empty: Do not use prefix
                    // otherwise, use the specified prefix
                    if (refAttr.Prefix != null)
                    {
                        if (refAttr.Prefix.Length > 0)
                        {
                            newPrefix = prefix + (refAttr.Prefix.EndsWith(".") ? refAttr.Prefix : refAttr.Prefix + ".");
                        }
                    }
                    else
                    {
                        // Try to get a smart default preifx if developer doesn't specify one.
                        // If the property name is like BrandId,
                        // then we use 'Brand' instead of 'BrandId'.
                        // So when we are investigating Brand.Name property, we can get a better parameter name 'BrandName' instead of 'BrandIdName'
                        if (property.Name.EndsWith("Id"))
                        {
                            newPrefix = prefix + property.Name.Substring(0, property.Name.Length - 2);
                        }
                        else
                        {
                            newPrefix = prefix + property.Name;
                        }

                        newPrefix = newPrefix + ".";
                    }

                    parameters.AddRange(FindConditionParameters(referencingType, resolver, newPrefix));

                    // Add also extended parameters
                    foreach (var provider in Providers)
                    {
                        if (provider.GetType() != typeof(DefaultRuleParameterProvider))
                        {
                            var additionalParams = provider.GetParameters(referencingType);
                            foreach (var param in additionalParams)
                            {
                                var valueResolver = new ChainedRuleParameterValueResolver();
                                valueResolver.Chain(resolver);
                                valueResolver.Chain(param.ValueResolver);

                                var adaptedParam = new RuleParameter(newPrefix + param.Name, param.ValueType, valueResolver, param.SupportedOperators)
                                {
                                    ValueSource = param.ValueSource
                                };

                                parameters.Add(adaptedParam);
                            }
                        }
                    }
                }
                else
                {
                    var paramAttr = property.GetCustomAttribute<ParamAttribute>(false);
                    if (paramAttr != null)
                    {
                        parameters.Add(CreateConditionParameter(containerType, containerResolver, prefix, property, paramAttr));
                    }
                }
            }

            return parameters;
        }