4

我编写了一个小应用程序来获取 .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 是否可能锁定文件?

4

3 回答 3

6

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

  1. 启动一个新的 AppDomain
  2. 在该应用程序域中加载程序集
  3. 仅在此处使用它-不要使用主应用程序域中程序集的任何类型。
  4. 调用AppDomain.Unload拆除 AppDomain
  5. 然后删除文件

当程序集加载到正在执行的 AppDomain 中时,您不能删除包含程序集的文件。

于 2012-05-25T16:37:29.193 回答
2

AssemblyName.GetAssemblyName将在AssemblyName不锁定文件的情况下获取对象。见msdn。您可以从那里获取版本。

于 2012-05-25T17:51:10.203 回答
1

另一种方法(除了在单独的 AppDomain 中使用从文件加载)是使用Assembly.Load 从文件的 MemoryStream 副本将程序集从字节加载到主 AppDomain。

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

即使使用单独的 AppDomain,对于您的方案,使用 LoadReflectionOnlyFrom 从字节加载也会更安全,因为在这种情况下,卸载 AppDomain 失败不会保持文件锁定,并且您自己可以完全控制文件的锁定。对于使用从字节加载的程序集的常规加载,需要大量阅读以了解相关问题并更好地避免。

于 2012-05-25T16:47:01.717 回答