我在Windows服务中运行以下代码,即使在严重并发的情况下,该服务已经运行多年没有问题:
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.OutputAssembly = outputAssemblyFile;
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, "file.cs");
if (results.Errors.Count > 0)
{
Console.WriteLine("Compile ERROR");
}
else
{
Console.WriteLine("Compile OK");
Console.WriteLine("Assembly Path:" + results.PathToAssembly);
Console.WriteLine("Assembly Name:" + results.CompiledAssembly.FullName);
}
通常,当代码成功编译时,由于parameters.GenerateInMemory设置为true,result.PathToAssembly为null(在MSDN中指定)
有一天我开始遇到一个问题,有时代码被成功编译但是results.PathToAssembly不为null。另外,CompiledAssembly正在返回FileNotFoundException,但是当我检查results.PathToAssembly指示的路径时,程序集实际上就在那里。但是,我无法确保它在那个特定时刻存在。
我重新启动了服务,一切都恢复正常。
有没有明显的理由发生这种情况?
认为这可能是一些权限问题我尝试通过已经创建程序集并将文件设置为只读来重现该问题,但这导致编译失败。
答案 0 :(得分:1)
我在GenerateInMemory==true
时读取文档的方式应该在内存中生成编译结果,而不生成EXE或DLL文件 - 因此result.PathToAssembly==null
。
在这种情况下,将OutputAssembly
设置为某些东西仍然有意义:即使汇编只是存在于内存中,它也会有一个名称。 GenerateExecutable
告诉系统生成EXE或DLL,因此如果结果在内存中则应忽略它。
这是我理解这个理论的方式 - 在实践中发生的是,无论GenerateInMemory
的值是什么,都会生成DLL o EXE文件,其名称由OutputAssembly
指定并放置在当前目录。
此外,似乎编译器对此文件执行多个操作 - delete / create / open / close。
这意味着如果多个线程同时调用编译器代码,它可能会因“找不到文件”或“正在使用文件”错误而失败,因为不同线程上的文件操作会相互干扰。
如果代码的目的是在磁盘上生成一个汇编文件,那么解决方案就是:
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = false;
并且不指定OutputAssembly
- 在这种情况下,系统将自动为程序集(和程序集DLL)生成唯一的名称,从而避免不同线程之间的冲突。可以在result.PathToAssembly
中访问该文件的路径。