/** * Executes the provided function `f` and tracks which observables are being accessed. * The tracking information is stored on the `derivation` object and the derivation is registered * as observer of any of the accessed observables. */ public static T TrackedDerivedFunction <T>(this IDerivation derivation, Func <T> func, object context) { // pre allocate array allocation + room for variation in deps // array will be trimmed by bindDependencies derivation.ChangeDependenciesStateTo0(); derivation.NewObservings = new List <IObservable>(derivation.Observings.Count + 100); derivation.UnboundDepsCount = 0; derivation.RunId = States.NextRunId; var previous = States.UntrackedStart(derivation); T result = default(T); if (States.State.DisableErrorBoundaries) { result = func(); } else { try { result = func(); } catch (Exception ex) { throw new CaughtException(ex); } } States.UntrackedEnd(previous); derivation.BindDependencies(); return(result); }
public static bool ShouldCompute(this IDerivation derivation) { switch (derivation.DependenciesState) { case DerivationState.UP_TO_DATE: return(false); case DerivationState.NOT_TRACKING: case DerivationState.STALE: return(true); case DerivationState.POSSIBLY_STALE: { var prevUntracked = States.UntrackedStart(); // no need for those computeds to be reported, they will be picked up in trackDerivedFunction. foreach (var observer in derivation.Observings) { if (observer is IComputedValue computed) { if (States.State.DisableErrorBoundaries) { var x = computed.Value; } else { try { var y = computed.Value; } catch { // we are not interested in the value *or* exception at this moment, but if there is one, notify all States.UntrackedEnd(prevUntracked); return(true); } } // if ComputedValue `obj` actually changed it will be computed and propagated to its observers. // and `derivation` is an observer of `obj` // invariantShouldCompute(derivation) if (derivation.DependenciesState == DerivationState.STALE) { States.UntrackedEnd(prevUntracked); return(true); } } } derivation.ChangeDependenciesStateTo0(); States.UntrackedEnd(prevUntracked); return(false); } default: return(false); } }