예제 #1
0
            private bool Equals(RoutePatternPart x, RoutePatternPart y)
            {
                if (x.GetType() != y.GetType())
                {
                    return(false);
                }

                if (x.IsLiteral && y.IsLiteral)
                {
                    return(Equals((RoutePatternLiteralPart)x, (RoutePatternLiteralPart)y));
                }
                else if (x.IsParameter && y.IsParameter)
                {
                    return(Equals((RoutePatternParameterPart)x, (RoutePatternParameterPart)y));
                }
                else if (x.IsSeparator && y.IsSeparator)
                {
                    return(Equals((RoutePatternSeparatorPart)x, (RoutePatternSeparatorPart)y));
                }

                Debug.Fail("This should not be reachable. Do you need to update the comparison logic?");
                return(false);
            }
예제 #2
0
        private static RoutePattern PatternCore(
            string rawText,
            IDictionary <string, object> defaults,
            IDictionary <string, object> constraints,
            IEnumerable <RoutePatternPathSegment> segments)
        {
            // We want to merge the segment data with the 'out of line' defaults and constraints.
            //
            // This means that for parameters that have 'out of line' defaults we will modify
            // the parameter to contain the default (same story for constraints).
            //
            // We also maintain a collection of defaults and constraints that will also
            // contain the values that don't match a parameter.
            //
            // It's important that these two views of the data are consistent. We don't want
            // values specified out of line to have a different behavior.

            var updatedDefaults = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);

            if (defaults != null)
            {
                foreach (var kvp in defaults)
                {
                    updatedDefaults.Add(kvp.Key, kvp.Value);
                }
            }

            var updatedConstraints = new Dictionary <string, List <RoutePatternConstraintReference> >(StringComparer.OrdinalIgnoreCase);

            if (constraints != null)
            {
                foreach (var kvp in constraints)
                {
                    updatedConstraints.Add(kvp.Key, new List <RoutePatternConstraintReference>()
                    {
                        Constraint(kvp.Value),
                    });
                }
            }

            var parameters      = new List <RoutePatternParameterPart>();
            var updatedSegments = segments.ToArray();

            for (var i = 0; i < updatedSegments.Length; i++)
            {
                var segment = VisitSegment(updatedSegments[i]);
                updatedSegments[i] = segment;

                for (var j = 0; j < segment.Parts.Count; j++)
                {
                    if (segment.Parts[j] is RoutePatternParameterPart parameter)
                    {
                        parameters.Add(parameter);
                    }
                }
            }

            return(new RoutePattern(
                       rawText,
                       updatedDefaults,
                       updatedConstraints.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList <RoutePatternConstraintReference>)kvp.Value.ToArray()),
                       parameters.ToArray(),
                       updatedSegments.ToArray()));

            RoutePatternPathSegment VisitSegment(RoutePatternPathSegment segment)
            {
                var updatedParts = new RoutePatternPart[segment.Parts.Count];

                for (var i = 0; i < segment.Parts.Count; i++)
                {
                    var part = segment.Parts[i];
                    updatedParts[i] = VisitPart(part);
                }

                return(SegmentCore(updatedParts));
            }

            RoutePatternPart VisitPart(RoutePatternPart part)
            {
                if (!part.IsParameter)
                {
                    return(part);
                }

                var parameter = (RoutePatternParameterPart)part;
                var @default  = parameter.Default;

                if (updatedDefaults.TryGetValue(parameter.Name, out var newDefault))
                {
                    if (parameter.Default != null)
                    {
                        var message = Resources.FormatTemplateRoute_CannotHaveDefaultValueSpecifiedInlineAndExplicitly(parameter.Name);
                        throw new InvalidOperationException(message);
                    }

                    if (parameter.IsOptional)
                    {
                        var message = Resources.TemplateRoute_OptionalCannotHaveDefaultValue;
                        throw new InvalidOperationException(message);
                    }

                    @default = newDefault;
                }

                if (parameter.Default != null)
                {
                    updatedDefaults.Add(parameter.Name, parameter.Default);
                }

                if (!updatedConstraints.TryGetValue(parameter.Name, out var parameterConstraints) &&
                    parameter.Constraints.Count > 0)
                {
                    parameterConstraints = new List <RoutePatternConstraintReference>();
                    updatedConstraints.Add(parameter.Name, parameterConstraints);
                }

                if (parameter.Constraints.Count > 0)
                {
                    parameterConstraints.AddRange(parameter.Constraints);
                }

                return(ParameterPartCore(
                           parameter.Name,
                           @default,
                           parameter.ParameterKind,
                           (IEnumerable <RoutePatternConstraintReference>)parameterConstraints ?? Array.Empty <RoutePatternConstraintReference>()));
            }
        }