#C# WPF .NET6 DLL 動的ロードについての調査事項
#AssemblyロードにてDLLを読み込む
#問題点
動的DLLをアプリケーション起動中に再ロードしてもオブジェクトが解放されな
い
#解決案
##AppDomainを使用しての解放
マイクロソフトのリファレンスから「.NET で使用できない.NET Framework テクノロジー」を参照 .NET は使用できない事が判明
##AssemblyLoadContextを使用しての解放
参考 URL https://www.ayumax.net/entry/2019/12/10/000000/
http://crocell01.blog18.fc2.com/blog-entry-173.html
https://learn.microsoft.com/ja-jp/dotnet/core/tutorials/creating-app-with-plugin-support
#コード
public class manage
{
static List<sampleInterface> CommadList;
public void LoadUnLoad()
{
string currentpath = System.IO.Directory.GetCurrentDirectory();
//CommadList = new List<sampleInterface>();
// プラグインパスチェック
if (currentpath != null && System.IO.Directory.Exists(currentpath))
{
// ディレクトリ内のDLLファイルパスを取得
foreach (string dll in Directory.GetFiles(currentpath, "ClassLibrary*.dll"))
{
ExecuteAndUnload(dll, out WeakReference alcWeakRef);
// アンロードされるまで待つ
int counter = 0;
for (counter = 0; alcWeakRef.IsAlive && (counter < 10); counter++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
if (counter < 10)
{
System.Diagnostics.Debug.WriteLine("アンロード成功");
}
else
{
System.Diagnostics.Debug.WriteLine("アンロード失敗");
}
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
void ExecuteAndUnload(string assemblyPath, out WeakReference alcWeakRef)
{
// アセンブリをロードするAssemblyLoadContextを作成
var alc = new TestAssemblyLoadContext();
// アセンブリをロード
Assembly a = alc.LoadFromAssemblyPath(assemblyPath);
// 外からアンロードを検知するために弱参照を設定
alcWeakRef = new WeakReference(alc, trackResurrection: true);
// リフレクションで関数コール
foreach (Type type in a.GetTypes())
{
// リフレクションで関数コール
Type t = type.GetInterfaces().FirstOrDefault((_t) => _t == typeof(sampleInterface));
if (t == default(sampleInterface)) continue;
// 取得した型のインスタンスを作成
var obj = Activator.CreateInstance(type);
//CommadList.Add(((sampleInterface)obj));
// 処理を実行
((sampleInterface)obj).sample2();
// アンロード実施
alc.Unload();
break;
}
}
}
#結果
アンロードはできたが、CommadList処理をメソッド内に含めるアンロードが失敗する
実際の使用方法は、ロードしたオブジェクトを使いまわしたい為、外部で保持する必要があるのだが、保持してしまうとアンロードが出来なくなることが分かった。
また、CommadListにnullを入れてもダメ、CommadListをロード、アンロードする内部で記述するだけでもアンロードができなかった。
本当に閉じた状態でしか使用ができないようだ。