3

コンパイルの完了後に.NETでCodeDomProviderクラスを使用する場合、出力アセンブリを削除することはできません。出力アセンブリを削除できるようにしたい。File.Deleteは、アクセス拒否の例外を返します。

string asmPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".exe");
string keyPath = "some path to a *.snk file that works";
// build compiler
CodeDomProvider dom = CodeDomProvider.CreateProvider("VisualBasic");
CompilerParameters cp = new CompilerParameters();
cp.TreatWarningsAsErrors = false;
cp.GenerateInMemory = false;
cp.GenerateExecutable = true;
cp.CompilerOptions = "/target:winexe /keyfile:\"" + keyPath + "\"";
cp.OutputAssembly = asmPath;
// add all the other assembly references
string netPath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\";
cp.ReferencedAssemblies.Add(netPath + @"System.dll");
cp.ReferencedAssemblies.Add(netPath + @"System.Core.dll");
cp.ReferencedAssemblies.Add(netPath + @"System.Data.dll");
cp.ReferencedAssemblies.Add(netPath + @"System.Xml.dll");
CompilerResults cr = dom.CompileAssemblyFromSource(cp, new string[] { code });
if (cr.Errors.Count == 0)
{
    cr.TempFiles.Delete();
    dom.Dispose();
// do stuff
...
//
    File.Delete(asmPath); // fails here Access Denied
}

編集回避策として、一時フォルダーを検索し、以前に作成されたアセンブリを削除するクラスで静的コンストラクターを使用しています。

4

1 に答える 1

3

問題は、アセンブリが(メモリに)ロードされ、出力ファイルが開いていることであると思われます。現在ロードされている他のアセンブリが実行可能ファイルへのハンドルを持っているのと同じです。

domインスタンスまたはCompilerResultsインスタンスが開いているファイルへの参照を持っている可能性もあります(可能性は低いと思いますが)。どちらもIDisposableそうではないので、ファイルを開いたままにしていないのではないかと思います。

可能な解決策:

アセンブリをメモリにコンパイルできます。つまり、ファイルを出力しないでください。それは当面の問題を解決します。ただし、コンパイルされたアセンブリがメモリに残っているという問題があります。アプリドメインを破棄せずにアセンブリをアンロードする方法はありません。

別のアプリドメインを作成してコンパイルを実行し、その結果をメインのアプリドメインに返すことができます。次に、コンパイラアプリドメインをシャットダウンできます。これにより、コンパイルされたアセンブリがメモリから削除され、作成したファイルを参照しているファイルハンドルも解放されます。その後、メインプログラムは問題のファイルを削除できます。

于 2011-05-17T22:56:32.760 に答える