/// <summary>This is a helper method for the caller's benefit. It flattens the tree. /// http://stackoverflow.com/questions/1938409/linq-how-to-convert-the-nested-hierarchical-object-to-flatten-object /// </summary> /// <param name="parent"></param> /// <returns></returns> private static IEnumerable<AssemblynameNode> Flatten(AssemblynameNode parent) { yield return parent; foreach (AssemblynameNode child in parent.ReferencedAssemblyNames ?? new List<AssemblynameNode>() ) { foreach (AssemblynameNode relative in Flatten(child)) { yield return relative; } } }
/// <summary>This is a helper method for the caller's benefit. It flattens the tree. /// http://stackoverflow.com/questions/1938409/linq-how-to-convert-the-nested-hierarchical-object-to-flatten-object /// </summary> /// <param name="parent"></param> /// <returns></returns> private static IEnumerable <AssemblynameNode> Flatten(AssemblynameNode parent) { yield return(parent); foreach (AssemblynameNode child in parent.ReferencedAssemblyNames ?? new List <AssemblynameNode>() ) { foreach (AssemblynameNode relative in Flatten(child)) { yield return(relative); } } }
/// <summary>This is the method for recursing through the AssemblyNames. /// It returns a tree of AssemblyNames. /// </summary> /// <param name="assembly"></param> /// <returns></returns> private static AssemblynameNode GetRecursive(Assembly assembly) { if (null == assembly) { throw new System.ArgumentNullException("assembly"); } // http://msdn.microsoft.com/en-us/magazine/cc163641.aspx <- reflection // http://dotnetdebug.net/2005/11/15/net-assembly-loader/ // http://stackoverflow.com/questions/3971793/what-when-assembly-getreferencedassemblies-returns-exe-dependency <- reflectiononlyload and ditto loadfrom. solves which problem? // We always have an AssemblyName to return. var ret = new AssemblynameNode(assembly.GetName()); // Loop through the AssemblyNames the actual Assembly references. Note that we might have already been into the AssemblyName through // another Assembly and then we have a circular reference which means stack overflow. It is taken care of in the loop. foreach (var assemblyname in assembly.GetReferencedAssemblies()) { // We only want to set the Info to have a list if we are sure we have referenced assemblies. If we don't have any referenced assemblies we will keep it as null. // If we are in the loop we know there are references Assemblies. Below is shorthand for making sure we have a List and not touch it if we already have a List. ret.ReferencedAssemblyNames = ret.ReferencedAssemblyNames ?? new List <AssemblynameNode>(); // Check if we alreay have found this Assemblyname. If we have; add it as a node but don't recurse its siblings. if (_assemblynameList.ContainsKey(assemblyname.FullName)) { ret.ReferencedAssemblyNames.Add(new AssemblynameNode(assemblyname)); } else { // The AssemblyName is new for us. // Add the AssemblyName to the list of AssemblyNames we have found. _assemblynameList.Add(assemblyname.FullName, assemblyname); // Gotta load the Assembly to get its references. Just AssemblyName won't do since AssemblyName doesn't have information about referenced Assemblies. { var ass = Assembly.Load(assemblyname.FullName); ret.ReferencedAssemblyNames.Add(GetRecursive(ass)); // ReSharper disable RedundantAssignment ass = null; // How do I unload? Can I? Should I? // ReSharper restore RedundantAssignment // Well... we can't unload in the default app domain. We should create a new, temporary, app domain and load/unload it there. // Not being able to unload means we have a memory leak for every call. // http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx } } } return(ret); }
/// <summary>This is the method for recursing through the AssemblyNames. /// It returns a tree of AssemblyNames. /// </summary> /// <param name="assembly"></param> /// <returns></returns> private static AssemblynameNode GetRecursive(Assembly assembly) { if (null == assembly) { throw new System.ArgumentNullException("assembly"); } // http://msdn.microsoft.com/en-us/magazine/cc163641.aspx <- reflection // http://dotnetdebug.net/2005/11/15/net-assembly-loader/ // http://stackoverflow.com/questions/3971793/what-when-assembly-getreferencedassemblies-returns-exe-dependency <- reflectiononlyload and ditto loadfrom. solves which problem? // We always have an AssemblyName to return. var ret = new AssemblynameNode(assembly.GetName()); // Loop through the AssemblyNames the actual Assembly references. Note that we might have already been into the AssemblyName through // another Assembly and then we have a circular reference which means stack overflow. It is taken care of in the loop. foreach (var assemblyname in assembly.GetReferencedAssemblies()) { // We only want to set the Info to have a list if we are sure we have referenced assemblies. If we don't have any referenced assemblies we will keep it as null. // If we are in the loop we know there are references Assemblies. Below is shorthand for making sure we have a List and not touch it if we already have a List. ret.ReferencedAssemblyNames = ret.ReferencedAssemblyNames ?? new List<AssemblynameNode>(); // Check if we alreay have found this Assemblyname. If we have; add it as a node but don't recurse its siblings. if (_assemblynameList.ContainsKey(assemblyname.FullName)) { ret.ReferencedAssemblyNames.Add(new AssemblynameNode(assemblyname)); } else { // The AssemblyName is new for us. // Add the AssemblyName to the list of AssemblyNames we have found. _assemblynameList.Add(assemblyname.FullName, assemblyname); // Gotta load the Assembly to get its references. Just AssemblyName won't do since AssemblyName doesn't have information about referenced Assemblies. { var ass = Assembly.Load(assemblyname.FullName); ret.ReferencedAssemblyNames.Add(GetRecursive(ass)); // ReSharper disable RedundantAssignment ass = null; // How do I unload? Can I? Should I? // ReSharper restore RedundantAssignment // Well... we can't unload in the default app domain. We should create a new, temporary, app domain and load/unload it there. // Not being able to unload means we have a memory leak for every call. // http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx } } } return ret; }