private void OnPropertyChanged(DeclaredProperty declaredProperty, object target, dynamic value, dynamic newValue) { if (target == null) { return; } MonitoringTree.HandleObservedChange ( termRelativeRoot: TermFromRoot, oldValue: value, newValue: newValue ); foreach (var definesTerm in declaredProperty.DefinesPropertyTerms) { var definesNewValue = definesTerm.GetValue ( target: target, actualKey: out _, parent: out var definesTarget, property: out var definesProperty ); var definesDeclaredProperty = (DeclaredProperty)definesProperty; definesDeclaredProperty.NotifyChange ( target: definesTarget, oldValue: default(UnknownValue), newValue: definesNewValue ); } }
internal PropertyLink(PropertyMonitoringTree monitoringTree, PropertyLink rootward, DeclaredProperty property) { MonitoringTree = monitoringTree; monitoringTree.AllLinks.Add(this); Rootward = rootward; Property = property; TermFromRoot = Term.Append(monitoringTree.Stub, GetTermFromRoot(monitoringTree.OutputTermComponentSeparator), false); HasUnresolvedIndexes = TermFromRoot.OfType <AnyIndexProperty>().Any(); }
/// <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) }); }
internal void EstablishPropertyDependancies(DeclaredProperty property) { if (property.HasAttribute <DefinesAttribute>(out var dAttribute) && dAttribute.Terms is string[] dArgs && dArgs.Any()) { foreach (var term in dArgs.Select(name => TermFactory.MakeOrGetCachedTerm(property.Owner, name, ".", TermBindingRule.OnlyDeclared))) { property.DefinesPropertyTerms.Add(term); } property.DefinesOtherProperties = true; } }
/// <summary> /// Converts all properties in this term to dynamic properties /// </summary> private static Term MakeDynamic(Term term) { if (term.IsDynamic) { return(term); } var newTerm = new Term(term.ComponentSeparator); newTerm.Store.AddRange(term.Store.Select(prop => prop switch { DynamicProperty _ => prop, DeclaredProperty _ => DynamicProperty.Parse(prop.Name), _ => throw new ArgumentOutOfRangeException() }));
/// <summary> /// Parses a declared property from a key string and a type /// </summary> /// <param name="type">The type to match the property from</param> /// <param name="key">The string to match a property from</param> /// <param name="declaredProperty">The declared property found</param> /// <returns></returns> public bool TryFindDeclaredProperty(Type type, string key, out DeclaredProperty declaredProperty) { return(GetDeclaredProperties(type).TryGetValue(key, out declaredProperty)); }