/// <summary> /// Evaluates the given expression and returns the result. The expression can refer to a local variable (e.g. 'somevariable'), /// a path starting from a localVariable (e.g. 'somevariable.SomeProperty.SomeOtherProperty'), or a path starting from the root /// data object (e.g. if the root was of type 'Person' you could say 'FirstName', assuming the Person type has a property called 'FirstName'). /// </summary> /// <param name="expressionText">The expression text</param> /// <returns>The resolved value as a .NET object</returns> public object EvaluateExpression(string expressionText) { object localVariableValue; string restOfExpressionText; ObjectPathExpression expression; object root; if (LocalVariables.TryParseLocalVariable(expressionText, out localVariableValue, out restOfExpressionText)) { if (restOfExpressionText == null) { return(localVariableValue); } else { expression = ObjectPathExpression.Parse(restOfExpressionText); root = localVariableValue; } } else { expression = ObjectPathExpression.Parse(expressionText); root = this.RootDataObject; } var ret = expression.Evaluate(root); return(ret); }
private IDisposable DeepSubscribeInternal(string path, Action handler, Lifetime rootLifetime = null) { rootLifetime = rootLifetime ?? new Lifetime(); var observableRoot = DeepObservableRoot ?? this; IObservableObject currentObservable = observableRoot; var pathExpression = ObjectPathExpression.Parse(path); List <IObjectPathElement> currentPath = new List <IObjectPathElement>(); var anyChangeLifetime = new Lifetime(); for (int i = 0; i < pathExpression.Elements.Count; i++) { var propertyElement = pathExpression.Elements[i] as PropertyPathElement; if (propertyElement == null) { throw new NotSupportedException("Indexers are not supported for deep observability"); } currentPath.Add(propertyElement); ObjectPathExpression.TraceNode eval; if (i == pathExpression.Elements.Count - 1 && propertyElement.PropertyName == ObservableObject.AnyProperty) { eval = new ObjectPathExpression.TraceNode() { Value = null }; } else { eval = new ObjectPathExpression(currentPath).EvaluateAndTraceInfo(observableRoot).Last(); if (i != pathExpression.Elements.Count - 1 && (eval.MemberInfo as PropertyInfo).PropertyType.GetInterfaces().Contains(typeof(IObservableObject)) == false) { throw new NotSupportedException($"element {eval.MemberInfo.Name} is not observable"); } } currentObservable.SubscribeForLifetime(propertyElement.PropertyName, () => { handler(); if (anyChangeLifetime.IsExpired == false) { anyChangeLifetime.Dispose(); } if (rootLifetime.IsExpired == false) { DeepSubscribeInternal(path, handler, rootLifetime); } }, EarliestOf(anyChangeLifetime, rootLifetime)); currentObservable = eval.Value as IObservableObject; if (currentObservable == null) { break; } } return(rootLifetime); }