私のプロジェクトは次のように設定されています。
プロジェクト「Consumer」は「Definition」と「Implementation」の両方を参照しますが、「Implementation」の型を静的に参照しません。
アプリケーションが起動すると、プロジェクト「Consumer」は「Definition」の静的メソッドを呼び出します。このメソッドは「Implementation」の型を見つける必要があります
パスまたは名前を知らずに、できれば本格的なIOCフレームワークを使用せずに、参照されたアセンブリをアプリドメインに強制的にロードする方法はありますか?
これはトリックを行うように見えました:
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
var loadedPaths = loadedAssemblies.Select(a => a.Location).ToArray();
var referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
var toLoad = referencedPaths.Where(r => !loadedPaths.Contains(r, StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(path => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
Jonが指摘したように、理想的なソリューションは、ロードされた各アセンブリの依存関係を再帰する必要がありますが、私の特定のシナリオでは、それについて心配する必要はありません。
更新: .NET 4に含まれるManaged Extensibility Framework(System.ComponentModel)には、このようなことを実現するための優れた機能があります。
_Assembly.GetReferencedAssemblies
_ を使用して_AssemblyName[]
_を取得し、それぞれでAssembly.Load(AssemblyName)
を呼び出すことができます。もちろん、再帰する必要があります-ただし、できれば既にロードしたアセンブリを追跡してください:)
再帰的な例を共有したかっただけです。スタートアップルーチンでLoadReferencedAssemblyメソッドを次のように呼び出しています。
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
this.LoadReferencedAssembly(Assembly);
}
これは再帰的な方法です:
private void LoadReferencedAssembly(Assembly assembly)
{
foreach (AssemblyName name in Assembly.GetReferencedAssemblies())
{
if (!AppDomain.CurrentDomain.GetAssemblies().Any(a => a.FullName == name.FullName))
{
this.LoadReferencedAssembly(Assembly.Load(name));
}
}
}
Fody.Costura、またはその他のアセンブリマージソリューションを使用する場合、受け入れられた答えは機能しません。
以下は、現在ロードされているアセンブリの参照アセンブリをロードします。再帰はあなたに任されています。
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
loadedAssemblies
.SelectMany(x => x.GetReferencedAssemblies())
.Distinct()
.Where(y => loadedAssemblies.Any((a) => a.FullName == y.FullName) == false)
.ToList()
.ForEach(x => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(x)));
今日、特定のパスからアセンブリ+依存関係を読み込む必要があるのを見て、それを行うためにこのクラスを作成しました。
public static class AssemblyLoader
{
private static readonly ConcurrentDictionary<string, bool> AssemblyDirectories = new ConcurrentDictionary<string, bool>();
static AssemblyLoader()
{
AssemblyDirectories[GetExecutingAssemblyDirectory()] = true;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
}
public static Assembly LoadWithDependencies(string assemblyPath)
{
AssemblyDirectories[Path.GetDirectoryName(assemblyPath)] = true;
return Assembly.LoadFile(assemblyPath);
}
private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
{
string dependentAssemblyName = args.Name.Split(',')[0] + ".dll";
List<string> directoriesToScan = AssemblyDirectories.Keys.ToList();
foreach (string directoryToScan in directoriesToScan)
{
string dependentAssemblyPath = Path.Combine(directoryToScan, dependentAssemblyName);
if (File.Exists(dependentAssemblyPath))
return LoadWithDependencies(dependentAssemblyPath);
}
return null;
}
private static string GetExecutingAssemblyDirectory()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
さらに別のバージョン( Daniel Schaffer answerに基づく)は、すべてのアセンブリをロードする必要はないが、事前定義された数のアセンブリをロードする必要がある場合です。
var assembliesToLoad = { "MY_SLN.PROJECT_1", "MY_SLN.PROJECT_2" };
// First trying to get all in above list, however this might not
// load all of them, because CLR will exclude the ones
// which are not used in the code
List<Assembly> dataAssembliesNames =
AppDomain.CurrentDomain.GetAssemblies()
.Where(Assembly => AssembliesToLoad.Any(a => Assembly.GetName().Name == a))
.ToList();
var loadedPaths = dataAssembliesNames.Select(a => a.Location).ToArray();
var compareConfig = StringComparison.InvariantCultureIgnoreCase;
var referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
.Where(f =>
{
// filtering the ones which are in above list
var lastIndexOf = f.LastIndexOf("\\", compareConfig);
var dllIndex = f.LastIndexOf(".dll", compareConfig);
if (-1 == lastIndexOf || -1 == dllIndex)
{
return false;
}
return AssembliesToLoad.Any(aName => aName ==
f.Substring(lastIndexOf + 1, dllIndex - lastIndexOf - 1));
});
var toLoad = referencedPaths.Where(r => !loadedPaths.Contains(r, StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(path => dataAssembliesNames.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
if (dataAssembliesNames.Count() != AssembliesToLoad.Length)
{
throw new Exception("Not all assemblies were loaded into the project!");
}