[英]Sort .NET Assemblies by dependencies
I have a set of .NET assemblies within my project. 我的项目中有一组.NET程序集。 I wish to sort them by their dependencies.
我希望按他们的依赖关系对它们进行排序。
So if I have (for example): 如果我有(例如):
IEnumerable<Assembly> unsorted = LoadAssembliesFromFolder();
I want to be able to call: 我希望能够打电话:
var IEnumerable<Assembly> sorted = unsorted.SortByDependency();
In reality, the resultant set would hopefully end up looking like the project build order dialog in Visual Studio. 实际上,结果集有望最终看起来像Visual Studio中的项目构建顺序对话框。
Any thoughts? 有什么想法吗? I don't really want to go down an iterative approach which could take quite some time.
我真的不想采用可能需要相当长时间的迭代方法。
Cheers 干杯
You will need to levarage the GetReferencedAssemblies()
method of Assembly
. 您将需要levrage
Assembly
的GetReferencedAssemblies()
方法。 This returns a list of AssemblyName
values and allows you to load the next assembly. 这将返回
AssemblyName
值列表,并允许您加载下一个程序集。 It's terribly inefficient, and will ensure that every assembly is loaded into memory, but it's something :-D 它非常低效,并且会确保每个程序集都加载到内存中,但它是:-D
class AssemblyReferenceComparison : IComparer<Assembly>
{
public int Compare(Assembly x, Assembly y)
{
if (x == y) return 0;
if (GetReferencesAssemblies(x).Contains(y)) return -1;
if (GetReferencesAssemblies(y).Contains(x)) return 1;
return 0;
}
private static IEnumerable<Assembly> GetReferencesAssemblies(Assembly a)
{
var referencedAssemblies = new HashSet<Assembly>();
FillReferencesAssemblies(a, referencedAssemblies);
return referencedAssemblies;
}
private static void FillReferencesAssemblies(Assembly a, HashSet<Assembly> referencedAssemblies)
{
referencedAssemblies.Add(a);
var directAssemblies = a.GetReferencedAssemblies()
.Select(name => Load(name))
.Where(asm => asm != null)
.Where(asm => !referencedAssemblies.Contains(asm))
.ToArray();
foreach (var directAssembly in directAssemblies)
{
FillReferencesAssemblies(directAssembly, referencedAssemblies);
}
}
[DebuggerStepThrough]
private static Assembly Load(AssemblyName name)
{
try { return Assembly.Load(name); }
catch { return null; }
}
}
To use: 使用:
var assemblies = LoadAssembliesFromFolder()
.OrderBy(a => a, new AssemblyReferenceComparison())
.ThenBy(a => a.FullName);
I found @Steven's answer too slow so I have come up with the following: 我发现@Steven的答案太慢了,所以我想出了以下内容:
public class AssemblyItem {
public Assembly Item { get; set; }
public IList<AssemblyItem> Dependencies { get; set; }
public AssemblyItem(Assembly item) {
Item = item;
Dependencies = new List<AssemblyItem>();
}
}
public static void Main() {
// Get the assemblies
var assemblyItems = BuildManager.GetReferencedAssemblies().Cast<Assembly>().OrderBy(a => a.FullName).Select(a => new AssemblyItem(a)).ToList();
// Add the dependencies
foreach (var item in assemblyItems) {
foreach (var reference in item.Item.GetReferencedAssemblies()) {
var dependency = assemblyItems.SingleOrDefault(i => i.Item.FullName == reference.FullName);
if (dependency != null)
item.Dependencies.Add(dependency);
}
}
// Sort the assemblies
var sortedAssemblyItems = assemblyItems.TSort(i => i.Dependencies);
}
It uses the TSort extension method from: 它使用TSort扩展方法:
https://stackoverflow.com/a/11027096/155899 https://stackoverflow.com/a/11027096/155899
For more information on how this works see the following article on Wikipedia: 有关其工作原理的更多信息,请参阅Wikipedia上的以下文章:
http://en.wikipedia.org/wiki/Topological_sort http://en.wikipedia.org/wiki/Topological_sort
I solved this like : 我解决了这个问题:
public class AssemblyInfo
{
public readonly Assembly Item;
public readonly IList<AssemblyInfo> ReferencedAssemblies;
public AssemblyInfo(Assembly item)
{
Item = item ?? throw new NullReferenceException("Item is null");
ReferencedAssemblies = new List<AssemblyInfo>();
}
int Count()
{
return ReferencedAssemblies.Count;
}
public override string ToString()
{
return Item.FullName;
}
public IEnumerable<AssemblyInfo> OrderedDependencies()
{
List<AssemblyInfo> localOrdered = new List<AssemblyInfo>();
foreach (AssemblyInfo item in ReferencedAssemblies.OrderBy(t => t.Count()))
{
IEnumerable<AssemblyInfo> temp = item.OrderedDependencies();
localOrdered = localOrdered.Union<AssemblyInfo>(temp).ToList();
}
localOrdered.Add(this);
return localOrdered;
}
public override bool Equals(object obj)
{
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(obj, null))
{
return false;
}
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(this, obj))
{
return true;
}
return Item.FullName.Equals(((AssemblyInfo)obj).Item.FullName);
}
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
return Item.FullName.GetHashCode();
}
public static AssemblyInfo Parse(string assembliesPath, string assemblyName)
{
return Parse(assembliesPath, assemblyName, new Dictionary<string, Assembly>());
}
static AssemblyInfo Parse(string assembliesPath, string assemblyName, Dictionary<string, Assembly> loadedAssemblies)
{
string assemblyFullPath = Path.Combine(assembliesPath, assemblyName);
if (!File.Exists(assemblyFullPath))
{
return null;
}
if (loadedAssemblies == null)
{
loadedAssemblies = new Dictionary<string, Assembly>();
}
if (!loadedAssemblies.ContainsKey(assemblyFullPath))
{
loadedAssemblies.Add(assemblyFullPath, Assembly.Load(File.ReadAllBytes(assemblyFullPath)));
}
Assembly a = loadedAssemblies[assemblyFullPath];
AssemblyInfo ai = new AssemblyInfo(a);
foreach (AssemblyName an in a.GetReferencedAssemblies())
{
AssemblyInfo d = Parse(assembliesPath, an.Name + ".dll", loadedAssemblies);
if (d != null)
{
ai.ReferencedAssemblies.Add(d);
}
}
return ai;
}
}
Use it : 用它 :
AssemblyInfo ai = AssemblyInfo.Parse("assembliesPath","yourassembly.dll");
IEnumerable<AssemblyInfo> sorted = ai.OrderedDependencies();
foreach (AssemblyInfo item in sorted)
{
Console.WriteLine(item.Item.ManifestModule.ToString());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.