Este método de extensión obtiene todos los ensamblados referenciados, de forma recursiva, incluidos los ensamblados anidados.
A medida que se usa ReflectionOnlyLoad
, carga los ensamblados en un AppDomain separado, lo que tiene la ventaja de no interferir con el proceso JIT.
Notarás que también hay un MyGetMissingAssembliesRecursive
. Puede usar esto para detectar los ensamblados faltantes a los que se hace referencia, pero que no están presentes en el directorio actual por alguna razón. Esto es increíblemente útil cuando se usa MEF . La lista de devolución le dará tanto el ensamblado que falta como quién es el propietario (su padre).
/// <summary>
/// Intent: Get referenced assemblies, either recursively or flat. Not thread safe, if running in a multi
/// threaded environment must use locks.
/// </summary>
public static class GetReferencedAssemblies
{
static void Demo()
{
var referencedAssemblies = Assembly.GetEntryAssembly().MyGetReferencedAssembliesRecursive();
var missingAssemblies = Assembly.GetEntryAssembly().MyGetMissingAssembliesRecursive();
// Can use this within a class.
//var referencedAssemblies = this.MyGetReferencedAssembliesRecursive();
}
public class MissingAssembly
{
public MissingAssembly(string missingAssemblyName, string missingAssemblyNameParent)
{
MissingAssemblyName = missingAssemblyName;
MissingAssemblyNameParent = missingAssemblyNameParent;
}
public string MissingAssemblyName { get; set; }
public string MissingAssemblyNameParent { get; set; }
}
private static Dictionary<string, Assembly> _dependentAssemblyList;
private static List<MissingAssembly> _missingAssemblyList;
/// <summary>
/// Intent: Get assemblies referenced by entry assembly. Not recursive.
/// </summary>
public static List<string> MyGetReferencedAssembliesFlat(this Type type)
{
var results = type.Assembly.GetReferencedAssemblies();
return results.Select(o => o.FullName).OrderBy(o => o).ToList();
}
/// <summary>
/// Intent: Get assemblies currently dependent on entry assembly. Recursive.
/// </summary>
public static Dictionary<string, Assembly> MyGetReferencedAssembliesRecursive(this Assembly assembly)
{
_dependentAssemblyList = new Dictionary<string, Assembly>();
_missingAssemblyList = new List<MissingAssembly>();
InternalGetDependentAssembliesRecursive(assembly);
// Only include assemblies that we wrote ourselves (ignore ones from GAC).
var keysToRemove = _dependentAssemblyList.Values.Where(
o => o.GlobalAssemblyCache == true).ToList();
foreach (var k in keysToRemove)
{
_dependentAssemblyList.Remove(k.FullName.MyToName());
}
return _dependentAssemblyList;
}
/// <summary>
/// Intent: Get missing assemblies.
/// </summary>
public static List<MissingAssembly> MyGetMissingAssembliesRecursive(this Assembly assembly)
{
_dependentAssemblyList = new Dictionary<string, Assembly>();
_missingAssemblyList = new List<MissingAssembly>();
InternalGetDependentAssembliesRecursive(assembly);
return _missingAssemblyList;
}
/// <summary>
/// Intent: Internal recursive class to get all dependent assemblies, and all dependent assemblies of
/// dependent assemblies, etc.
/// </summary>
private static void InternalGetDependentAssembliesRecursive(Assembly assembly)
{
// Load assemblies with newest versions first. Omitting the ordering results in false positives on
// _missingAssemblyList.
var referencedAssemblies = assembly.GetReferencedAssemblies()
.OrderByDescending(o => o.Version);
foreach (var r in referencedAssemblies)
{
if (String.IsNullOrEmpty(assembly.FullName))
{
continue;
}
if (_dependentAssemblyList.ContainsKey(r.FullName.MyToName()) == false)
{
try
{
var a = Assembly.ReflectionOnlyLoad(r.FullName);
_dependentAssemblyList[a.FullName.MyToName()] = a;
InternalGetDependentAssembliesRecursive(a);
}
catch (Exception ex)
{
_missingAssemblyList.Add(new MissingAssembly(r.FullName.Split(',')[0], assembly.FullName.MyToName()));
}
}
}
}
private static string MyToName(this string fullName)
{
return fullName.Split(',')[0];
}
}
Actualizar
Para que este subproceso de código sea seguro, coloque un lock
. Actualmente no es seguro para subprocesos de forma predeterminada, ya que hace referencia a una variable global estática compartida para hacer su magia.