无法删除程序集(.exe)

时间:2012-05-25 16:31:43

标签: c# assemblies

我写了一个小应用程序来获取.cab文件中包含的文件版本号。

我将所有文件从cab提取到临时目录,然后遍历所有文件并检索版本号,如下所示:

//Attempt to load .net assembly to retrieve information
Assembly assembly = Assembly.LoadFile(tempDir + @"\" + renameTo);
Version version = assembly.GetName().Version;
DataRow dr = dt.NewRow();
dr["Product"] = renameTo;
dr["Version"] = version.ToString();
dt.Rows.Add(dr); 

然后,当我完成后,我想删除所有已提取的文件,如下所示:

        foreach (string filePath in filePaths)
        {
            //Remove read-only attribute if set
            FileAttributes attributes = File.GetAttributes(filePath);

            if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                File.SetAttributes(filePath, attributes ^ FileAttributes.ReadOnly);
            }

            File.Delete(filePath);
        }

这适用于所有文件,除了有时在.net .exe上失败。我可以手动删除该文件,使其看起来不会被锁定。

我应该寻找什么来使这项工作? Assembly.LoadFile可能是锁定文件吗?

3 个答案:

答案 0 :(得分:6)

Assembly.LoadFile确实锁定了文件。如果您需要从文件加载程序集然后删除文件,您需要做的是:

  1. Start a new AppDomain
  2. 在该appdomain中加载程序集
  3. 仅在此处使用它 - 不要在主应用程序域中使用程序集中的任何类型。
  4. 致电AppDomain.Unload以拆除AppDomain
  5. 然后删除文件
  6. 当程序集加载到正在执行的AppDomain中时,无法删除包含程序集的文件。

答案 1 :(得分:2)

AssemblyName.GetAssemblyName将获取AssemblyName对象,而不会将文件锁定在您身上。见msdn。你可以从那里得到版本。

答案 2 :(得分:1)

另一种方法(除了在单独的AppDomain中使用Load from file之外)是使用Assembly.Load from bytes将文件的MemoryStream副本加载到主AppDomain中。

请注意,要使代码完全正确,如果在一个文件中存在具有相同标识的程序集(即具有相同文件名的2个非强签名程序集),则每个程序集仍可能需要单独的AppDomain。

即使使用单独的AppDomain,使用LoadReflectionOnlyFrom为您的方案加载字节也会更安全,因为在这种情况下,卸载AppDomain失败的可能性会导致文件被锁定并且您可以完全控制自己锁定文件。对于使用字节加载来定期加载程序集需要大量读取才能理解相关问题,最好避免使用。