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); }
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>())); } }