public static T _runCycle <T>(T source, List <EnsureHistoryItem> history) where T : class, IImmutable { var rootContext = new EnsureContext(source); var plan = _createPlan(rootContext); foreach (var step in plan) { var res = _callMethod(step.method, step.context); if (!ReferenceEquals(step.context.Entity, res)) { // Ensure made changes, so the cycle needs to restart var changedSource = step.context.ApplyNewValue(res) as T; if (history != null) { var item = new EnsureHistoryItem( ensureMethod: step.method.Name, before: source, after: changedSource, context: step.context ); history.Add(item); } return(changedSource); } } return(source); }
public EnsureContext(object root) { _parent = null; _entity = root; _property = null; _index = -1; _findTypeOfCurrent(); }
public EnsureHistoryItem( string ensureMethod = "", object before = null, object after = null, EnsureContext context = null) { EnsureMethod = ensureMethod; Before = before; After = after; Context = context; }
public EnsureContext(EnsureContext parent, PropertyInfo property) { if (parent._type != CurrentType.Object) { throw new InvalidOperationException(); } _parent = parent; _index = -1; _property = property; _entity = property.AsGetter <object, object>().Invoke(_parent._entity); _findTypeOfCurrent(); }
public EnsureContext(EnsureContext parent, int index) { if (parent._type != CurrentType.List) { throw new InvalidOperationException(); } _parent = parent; _index = index; _property = null; var source = _parent._entity as IList; _entity = source[index]; _findTypeOfCurrent(); }
public static object _callMethod(MethodInfo method, EnsureContext context) { // the method should only be called if the conditions apply, so first we allow each condition to run and prevent calling the ensurer var conditions = _conditionsPerEnsurer[method]; foreach (var condition in conditions) { var res = condition.Lambda(context); if (res != condition.ExpectedValue) { return(context.Entity); // return the original entity of he context } } // if we have got here, all conditions apply, so we can run the ensurer itself var lambda = _ensureLambdas[method]; var result = lambda(context); return(result); }
public static IEnumerable <(int index, EnsureContext context, MethodInfo method)> _createPlan(EnsureContext rootContext) { var allContexts = rootContext.FlattenSubContexts(); return(allContexts .SelectMany(ctxt => _ensureMethodsForType(ctxt.Entity.GetType()) .Select(method => (context: ctxt, method: method))) .Select((pair, index) => (index: index, context: pair.context, method: pair.method))); }