【问题标题】:How can I properly rename assemblies after they're been compiled?编译后如何正确重命名程序集?
【发布时间】:2020-06-04 20:45:21
【问题描述】:

构建类库后,我的 bin/Debug 目录中有几个 .dll(一些来自我自己的项目,而另一些来自第三方库)。例如,

MyLibrary.dll
Newtonsoft.Json.dll
NLog.dll

我想重命名这些程序集,以便它们包含它们的版本号。例如,

MyLibrary-1.0.0.0.dll
Newtonsoft.Json-10.0.3.0.dll
NLog-2.0.0.0.dll

最好的方法是什么?我不能只重命名文件。我需要自己更改程序集名称,并将这些更改传播到依赖它们的任何东西。

到目前为止,我已经找到了以下解决方案(参见https://stackoverflow.com/a/21753873/1383366):

ildasm /all /out=MyLibrary.il MyLibrary.dll
ilasm /dll /out=MyLibrary-1.0.0.0.dll MyLibrary.il

我不仅不确定这是否足以正确更改程序集名称,而且我不知道传播名称更改的最佳方式。

【问题讨论】:

  • 为什么需要这样做以及目前使用的是哪个 .NET 版本?
  • 在 Linux 上,他们使用版本扩展名命名文件,并将简单名称链接到版本化名称。这样,您可以轻松恢复。
  • @PavelAnikhouski 我们在大多数项目中使用 .NET 4.0,而一些项目使用 .NET 4.5。我们想要这样做的原因:我们的库是第三方应用程序(在我们控制之外)的插件,它将我们的库加载到主 AppDomain 中。我们不希望与可能引用某些相同库的其他插件产生任何冲突。
  • 所以你选择了最糟糕的解决方案来解决我们一无所知的问题。看看 ILMerge 实用程序吧。
  • @HansPassant 我没有选择解决方案。我寻求帮助,并试图通过展示我找到的解决方案来提供帮助。如果我的问题不清楚,您可以通过询问要澄清的内容来帮助我。我会研究一下ILMerge。谢谢。

标签: c# .net visual-studio .net-assembly


【解决方案1】:

我认为在使用它们编译项目之后重命名引用不是一个好主意,并且不确定为什么你认为需要这样做。这可能表明这是对其他问题的解决方案 (XY problem?)。也许更好的数据包管理器会有所帮助 - Paket

无论如何,您可以使用Mono.Cecil 重命名引用。

一个快速而肮脏的例子如下:

string fileName = args[0];
string path = Path.GetDirectoryName(fileName);
var program = AssemblyDefinition.ReadAssembly(fileName);

foreach (var reference in program.Modules[0].AssemblyReferences)
{
    var referenceFile = Path.Combine(path, reference.Name+".dll");
    if (!File.Exists(referenceFile)) continue;

    var assemblyReference = AssemblyDefinition.ReadAssembly(referenceFile);

    var newReferenceName = $"{Path.GetFileNameWithoutExtension(referenceFile)}-{assemblyReference.Name.Version}";
    var newReferenceFile = Path.Combine(path, $"{newReferenceName}{Path.GetExtension(referenceFile)}");

    var assembly = assemblyReference.MainModule.Assembly;
    assembly.MainModule.Name = Path.GetFileName(newReferenceFile);
    assemblyReference.Write(newReferenceFile);       
}

program.Write(Path.Combine(path, "rewritten.exe"));

我们所做的只是重命名文件名 - 添加一个版本并更改每个程序集指向磁盘的名称。将所有重命名保留在与主程序集相同的文件夹中,以仅包含本地引用。

在一个带有项目参考和NuGetNLogNewtonsoft.Json,如您的示例)的小示例上进行了测试,它在重写后工作,但请记住,它只是处理直接引用并进入引用的引用,如果存在,您需要将此示例扩展到您的需要。

【讨论】:

  • 谢谢。在发布我的问题后,我实际上找到了 Mono.Cecil,并且我实现了一些与您的代码非常相似的东西(除了它是递归处理引用的引用)。我认为我需要 这样做的原因(我看不到其他方法)是我的程序集将作为插件加载到更大应用程序的 AppDomain 中。我不希望与加载到同一个 AppDomain 的其他插件发生冲突。例如,我的插件和别人的插件可能使用不同版本的 NLog。您是否看到了另一种处理方式?
  • 分离子文件夹和 AssemblyResolve 事件?也许重命名是最好的选择,但框架中有一些解决这个问题的可能性,我会在解决外部定制解决方案之前尝试它们,因为这样更容易出错。
猜你喜欢
  • 1970-01-01
  • 2016-01-17
  • 1970-01-01
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多