using System; using System.Collections.Generic; using System.IO; using System.Linq; using ModestTree; namespace Zenject { // Responsibilities: // - Output a file specifying the full object graph for a given root dependency // - This file uses the DOT language with can be fed into GraphViz to generate an image // - http://www.graphviz.org/ public static class ObjectGraphVisualizer { public static void OutputObjectGraphToFile( DiContainer container, string outputPath, IEnumerable externalIgnoreTypes, IEnumerable contractTypes) { // Output the entire object graph to file var graph = CalculateObjectGraph(container, contractTypes); var ignoreTypes = new List { typeof(DiContainer), typeof(InitializableManager) }; ignoreTypes.AddRange(externalIgnoreTypes); var resultStr = "digraph { \n"; resultStr += "rankdir=LR;\n"; foreach (var entry in graph) { if (ShouldIgnoreType(entry.Key, ignoreTypes)) { continue; } foreach (var dependencyType in entry.Value) { if (ShouldIgnoreType(dependencyType, ignoreTypes)) { continue; } resultStr += GetFormattedTypeName(entry.Key) + " -> " + GetFormattedTypeName(dependencyType) + "; \n"; } } resultStr += " }"; File.WriteAllText(outputPath, resultStr); } static bool ShouldIgnoreType(Type type, List ignoreTypes) { return ignoreTypes.Contains(type); } static Dictionary> CalculateObjectGraph( DiContainer container, IEnumerable contracts) { var map = new Dictionary>(); foreach (var contractType in contracts) { var depends = GetDependencies(container, contractType); if (depends.Any()) { map.Add(contractType, depends); } } return map; } static List GetDependencies( DiContainer container, Type type) { var dependencies = new List(); foreach (var contractType in container.GetDependencyContracts(type)) { List dependTypes; if (contractType.FullName.StartsWith("System.Collections.Generic.List")) { var subTypes = contractType.GenericArguments(); Assert.IsEqual(subTypes.Length, 1); var subType = subTypes[0]; dependTypes = container.ResolveTypeAll(subType); } else { dependTypes = container.ResolveTypeAll(contractType); Assert.That(dependTypes.Count <= 1); } foreach (var dependType in dependTypes) { dependencies.Add(dependType); } } return dependencies; } static string GetFormattedTypeName(Type type) { var str = type.PrettyName(); // GraphViz does not read names with <, >, or . characters so replace them str = str.Replace(">", "_"); str = str.Replace("<", "_"); str = str.Replace(".", "_"); return str; } } }