/// <summary> /// Parses a term key string and returns a term describing it. All terms are created here. /// The main caller is TypeCache.MakeTerm, but it's also called from places that use a /// dynamic domain (processors). /// </summary> public Term Parse(Type resource, string key, string componentSeparator, TermBindingRule bindingRule, ICollection <string> dynDomain) { var term = new Term(componentSeparator); Property propertyMaker(string str) { if (string.IsNullOrWhiteSpace(str)) { throw new InvalidSyntax(ErrorCodes.InvalidConditionSyntax, $"Invalid condition '{str}'"); } if (dynDomain?.Contains(str, StringComparer.OrdinalIgnoreCase) == true) { return(DynamicProperty.Parse(str)); } Property make(Type type) { switch (bindingRule) { case TermBindingRule.DeclaredWithDynamicFallback: try { return(TypeCache.FindDeclaredProperty(type, str)); } catch (UnknownProperty) { return(DynamicProperty.Parse(str)); } case TermBindingRule.DynamicWithDeclaredFallback: return(DynamicProperty.Parse(str, true)); case TermBindingRule.OnlyDeclared: try { return(TypeCache.FindDeclaredProperty(type, str)); } catch (UnknownProperty) { if (type.GetSubclasses().Any(subClass => TypeCache.TryFindDeclaredProperty(subClass, str, out _))) { return(DynamicProperty.Parse(str)); } throw; } default: throw new Exception(); } } return(term.LastOrDefault() switch { null => make(resource), DeclaredProperty declared => make(declared.Type), _ => DynamicProperty.Parse(str) }); }
/// <summary> /// Creates a new term for the given type, with the given key, component separator and binding rule. If a term with /// the given key already existed, simply returns that one. /// </summary> public Term MakeOrGetCachedTerm(Type resource, string key, string componentSeparator, TermBindingRule bindingRule) { var tuple = (resource.GetRESTableTypeName(), key.ToLower(), bindingRule); if (!TermCache.TryGetValue(tuple, out var term)) { term = TermCache[tuple] = Parse(resource, key, componentSeparator, bindingRule, null); } return(term); }