public void DetectMinimumCircularDependencyBetweenTwoNodes() { var a = new Node { Name = "A" }; var b = new Node { Name = "B" }; a.Edges.Add(b); b.Edges.Add(a); var roots = new Roots(); roots.Entangle(a); var serializers = new Serializers(new SerializerFactory()); var stateMaps = new StateMaps(serializers); var persister = new Persister(new InMemoryStorageEngine(), roots, serializers, stateMaps); persister.DetectSerializeAndPersistChanges(); var circularChain = CircularDependencyDetector.Check(serializers[0], stateMaps, serializers); circularChain.IsCircular.ShouldBeTrue(); circularChain.Path.Count().ShouldBe(3); circularChain.ToString().ShouldBe("A->B->A"); }
public void DetectCircularDependencyInComplexGraph() { var a = new Node { Name = "A" }; var b = new Node { Name = "B" }; var c = new Node { Name = "C" }; var d = new Node { Name = "D" }; var e = new Node { Name = "E" }; var f = new Node { Name = "F" }; var g = new Node { Name = "G" }; var h = new Node { Name = "H" }; a.Add(b); a.Add(c); c.Add(g); c.Add(f); g.Add(b); b.Add(d); d.Add(h); d.Add(f); f.Add(e); e.Add(d); var roots = new Roots(); roots.Entangle(a); var serializers = new Serializers(new SerializerFactory()); var stateMaps = new StateMaps(serializers); var persister = new Persister(new InMemoryStorageEngine(), roots, serializers, stateMaps); persister.DetectSerializeAndPersistChanges(); var circularChain = CircularDependencyDetector.Check(serializers[0], stateMaps, serializers); circularChain.IsCircular.ShouldBe(true); circularChain.Path.Count().ShouldBe(4); circularChain.ToString().ShouldBe("F->E->D->F"); }
private void GenerateBaseExpression(ServiceBinding serviceBinding, CircularDependencyDetector circularDependencyDetector) { if (serviceBinding.BaseExpression == null) { lock (serviceBinding) { if (serviceBinding.BaseExpression == null) { if (serviceBinding.Expression == null) { var constructor = serviceBinding.ConstructorResolver.DynamicSelectConstructor(serviceBinding.ConcreteType, this); serviceBinding.Expression = serviceBinding.ConcreteType.ResolveConstructorExpression(constructor); } ParameterExpression[] parameters = serviceBinding.Expression.GetParameterExpressions().Where(x => x.Type != ExpressionGenerator.ScopeParameter.Type).ToArray(); InstanceFactory[] factories = ResolveParameters(parameters, circularDependencyDetector); serviceBinding.BaseExpression = _expressionGenerator.GenerateBaseExpression(serviceBinding, factories, _containerScope, Settings); } } } }
public void DetectSerializeAndPersistChanges(bool checkForCircularDependencies = false) { var detectedChanges = DetectChanges(); if (detectedChanges.GarbageCollectableIds.Empty() && detectedChanges.RemovedEntries.Empty() && detectedChanges.NewEntries.Empty()) { return; } if (checkForCircularDependencies) { var(isCircular, path) = CircularDependencyDetector.Check(root: _serializers[0], _stateMaps, _serializers); if (isCircular) { throw new CircularDependencyException(path); } } _storageEngine.Persist(detectedChanges); }
public void DetectCircularDependencyOneNodeHavingMultipleOutgoingEdges() { var a = new Node { Name = "A" }; var b = new Node { Name = "B" }; var c = new Node { Name = "C" }; var d = new Node { Name = "D" }; a.Edges.Add(b); a.Edges.Add(d); b.Edges.Add(c); c.Edges.Add(b); var roots = new Roots(); roots.Entangle(a); var serializers = new Serializers(new SerializerFactory()); var stateMaps = new StateMaps(serializers); var persister = new Persister(new InMemoryStorageEngine(), roots, serializers, stateMaps); persister.DetectSerializeAndPersistChanges(); var circularChain = CircularDependencyDetector.Check(serializers[0], stateMaps, serializers); circularChain.IsCircular.ShouldBeTrue(); circularChain.Path.Count().ShouldBe(3); circularChain.ToString().ShouldBe("B->C->B"); }
public void ThrowOnCircularDependency_throws_exception_when_there_is_a_circular_dependency(IServiceRegistration registration1, IServiceRegistration registration2, IServiceRegistration registration3, CircularDependencyDetector sut) { // Arrange var path = new ResolutionPath(new [] { registration1, registration2, registration3 }); // Act & assert Assert.That(() => sut.ThrowOnCircularDependency(registration2, path), Throws.InstanceOf <CircularDependencyException>()); }
public void ThrowOnCircularDependency_does_not_throw_when_there_is_no_circular_dependency(IServiceRegistration registration1, IServiceRegistration registration2, IServiceRegistration registration3, CircularDependencyDetector sut) { // Arrange var path = new ResolutionPath(new [] { registration1, registration2 }); // Act & assert Assert.That(() => sut.ThrowOnCircularDependency(registration3, path), Throws.Nothing); }
public void HasCircularDependency_returns_true_when_there_is_a_circular_dependency(IServiceRegistration registration1, IServiceRegistration registration2, IServiceRegistration registration3, CircularDependencyDetector sut) { // Arrange var path = new ResolutionPath(new [] { registration1, registration2, registration3 }); // Act var result = sut.HasCircularDependency(registration2, path); // Assert Assert.That(result, Is.True); }
private InstanceFactory[] ResolveParameters(ParameterExpression[] parameters, CircularDependencyDetector circularDependencyDetector) { var factories = new InstanceFactory[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { ParameterExpression parameter = parameters[i]; ServiceBinding child = GetDependency(parameter.Type).Default; InstanceFactory? factory = TryResolveDependency(parameter.Type, child, circularDependencyDetector); factories[i] = factory ?? throw (child.ResolveError ?? throw new NotImplementedException()); } return(factories); }
private InstanceFactory GenerateInstanceFactory(Type type, ServiceBinding serviceBinding, CircularDependencyDetector circularDependencyDetector) { lock (serviceBinding) { if (!serviceBinding.TryGetInstanceFactory(type, out InstanceFactory factory)) { Expression[] decorators = FindDecorators(type); ParameterExpression[] parameters = decorators.GetParameterExpressions().Where(x => x.Type != ExpressionGenerator.ScopeParameter.Type && x.Type != type).ToArray(); InstanceFactory[] factories = ResolveParameters(parameters, circularDependencyDetector); ReadOnlyExpressionContext context = _expressionGenerator.ApplyDecorators(type, serviceBinding, factories, decorators, _containerScope); factory = new InstanceFactory(type, context); serviceBinding.Factories.Add(factory); } return(factory); } }
private InstanceFactory?TryResolveDependency(Type type, ServiceBinding dependency, CircularDependencyDetector circularDependencyDetector) { try { Settings.Logger.Log($"{nameof(TryResolveDependency)} for {type}", circularDependencyDetector.Count); circularDependencyDetector.Enter(type); if (type.IsGenericType && type.ContainsGenericParameters) { throw new OpenGenericTypeResolveException($"Cannot create a instance for type {type} since its registered as a abstract binding and not meant to be used directly."); } GenerateBaseExpression(dependency, circularDependencyDetector); InstanceFactory factory = GenerateInstanceFactory(type, dependency, circularDependencyDetector); return(factory); } catch (Exception e) { dependency.ResolveError = new DependencyResolveException(type, dependency, e); return(null); } finally { circularDependencyDetector.Leave(type); } }