C# 按依赖项对.NET程序集进行排序
我的项目中有一组.NET程序集。我希望按照它们的依赖关系对它们进行排序 因此,如果我有(例如):C# 按依赖项对.NET程序集进行排序,c#,.net,reflection,C#,.net,Reflection,我的项目中有一组.NET程序集。我希望按照它们的依赖关系对它们进行排序 因此,如果我有(例如): IEnumerable unsorted=LoadAssembliesFromFolder(); 我想打电话: var IEnumerable<Assembly> sorted = unsorted.SortByDependency(); var IEnumerable sorted=unsorted.sortbydependence(); 事实上,结果集有望最终看起来像Visua
IEnumerable unsorted=LoadAssembliesFromFolder();
我想打电话:
var IEnumerable<Assembly> sorted = unsorted.SortByDependency();
var IEnumerable sorted=unsorted.sortbydependence();
事实上,结果集有望最终看起来像VisualStudio中的“项目构建顺序”对话框
有什么想法吗?我真的不想采用迭代方法,这可能需要相当长的时间
干杯您需要提升
程序集
的getReferencedAssemblys()
方法。这将返回AssemblyName
值的列表,并允许您加载下一个程序集。这是非常低效的,并将确保每个程序集都加载到内存中,但它是:-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; }
}
}
我发现@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);
}
公共类AssemblyItem{
公共程序集项{get;set;}
公共图书馆
有关此操作的更多信息,请参阅维基百科上的以下文章:
我像这样解决了这个问题:
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;
}
}
公共类AssemblyInfo
{
公共只读程序集项;
公共只读IList ReferencedAssembly;
公共装配信息(装配项目)
{
Item=Item??抛出新的NullReferenceException(“Item为null”);
ReferencedAssemblys=新列表();
}
整数计数()
{
返回referencedAssemblys.Count;
}
公共重写字符串ToString()
{
返回Item.FullName;
}
公共IEnumerable OrderedDependencies()
{
List localOrdered=新列表();
foreach(ReferencedAssemblys.OrderBy(t=>t.Count())中的AssemblyInfo项)
{
IEnumerable temp=item.OrderedDependencies();
localOrdered=localOrdered.Union(temp.ToList();
}
localOrdered.Add(这个);
返回本地订单;
}
公共覆盖布尔等于(对象对象对象)
{
//检查是否有任何比较对象为空。
if(Object.ReferenceEquals(obj,null))
{
返回false;
}
//检查比较对象是否引用相同的数据。
if(Object.ReferenceEquals(this,obj))
{
返回true;
}
返回Item.FullName.Equals(((AssemblyInfo)obj.Item.FullName);
}
公共覆盖int GetHashCode()
{
//如果名称字段不为null,则获取其哈希代码。
return Item.FullName.GetHashCode();
}
公共静态AssemblyInfo解析(字符串AssemblyPath、字符串assemblyName)
{
返回Parse(assembliesPath,assemblyName,newdictionary());
}
静态AssemblyInfo解析(字符串AssemblyPath、字符串assemblyName、字典加载的Assemblys)
{
字符串assemblyFullPath=Path.Combine(assembliesPath,assemblyName);
如果(!File.Exists(assemblyFullPath))
{
返回null;
}
如果(loadedAssemblies==null)
{
loadedAssemblies=新字典();
}
如果(!LoadedAssembly.ContainsKey(assemblyFullPath))
{
loadedAssemblies.Add(assemblyFullPath,Assembly.Load(File.ReadAllBytes(assemblyFullPath));
}
组件a=加载的组件[assemblyFullPath];
AssemblyInfo ai=新的AssemblyInfo(a);
foreach(a.GetReferencedAssemblys()中的AssemblyName)
{
AssemblyInfo d=Parse(assembliesPath,一个.Name+“.dll”,loadedsassemblies);
如果(d!=null)
{
ai.参考组件。添加(d);
}
}
返回ai;
}
}
使用它:
AssemblyInfo ai = AssemblyInfo.Parse("assembliesPath","yourassembly.dll");
IEnumerable<AssemblyInfo> sorted = ai.OrderedDependencies();
foreach (AssemblyInfo item in sorted)
{
Console.WriteLine(item.Item.ManifestModule.ToString());
}
AssemblyInfo ai=AssemblyInfo.Parse(“assembliesPath”、“yoursassembly.dll”);
IEnumerable sorted=ai.OrderedDependencies();
foreach(已排序的AssemblyInfo项)
{
WriteLine(item.item.ManifestModule.ToString());
}
我认为这里没有迭代以外的其他方法。您需要算法吗?您希望如何处理循环引用?(例如,框架中的System
和System.Xml
相互引用)好问题-我不需要对系统库进行排序,只需要对我自己的库进行排序,但我怀疑在我的库集中,循环引用只存在于库的相同“级别”(即相似的依赖项集),这意味着两者之间的顺序并不重要。
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;
}
}
AssemblyInfo ai = AssemblyInfo.Parse("assembliesPath","yourassembly.dll");
IEnumerable<AssemblyInfo> sorted = ai.OrderedDependencies();
foreach (AssemblyInfo item in sorted)
{
Console.WriteLine(item.Item.ManifestModule.ToString());
}