程序集加载版本不匹配:为什么要加载?

时间:2011-05-04 12:38:44

标签: .net assemblies dll

我有两个程序集:HelloWorld.exe和Hello.dll。 exe是主程序集,主程序集正在使用dll。

我编译了HelloWorld.exe(1.0.0)和Hello.dll(1.0.0)。我将程序集放在不同的文件夹中。

然后我将Hello.dll的版本更改为2.0.0并继续使用2.0.0版本覆盖Hello.dll 1.0.0。然后我启动HelloWorld.exe,它工作正常。

我预计它会崩溃并立即刻录,因为编译EXE时引用的Hello.dll是1.0.0。现在,1.0.0 DLL已被2.0.0取代,但它仍然有效!

根据MSDN

  

默认情况下,程序集仅使用完全相同的类型   用它构建和测试的程序集(名称和版本号)。   也就是说,如果您的程序集使用版本1.0.0.2中的类型   另一个程序集,它将(默认情况下)不使用相同的类型   另一个程序集的1.0.0.4版。这个使用名称和   用于识别引用程序集的版本有助于避免“DLL Hell”   升级到一个应用程序破坏其他应用程序的问题。

问题:

  1. 为什么会这样?
  2. 如何使它不起作用?
  3. 奖金问题:构建过程中会发生什么?外部依赖项的版本是否硬编码为主依赖项?
  4. 请注意,Hello.dll没有强名称。

    这是HelloWorld.exe的清单:

    // Metadata version: v2.0.50727
    .assembly extern mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
      .ver 2:0:0:0
    }
    .assembly extern Hello
    {
      .ver 2:0:0:0
    }
    .assembly HelloWorld
    {
    ...//snipped
    }
    

    这是从Fuslogvw.exe(程序集绑定日志查看器)中获取的程序集绑定日志:

    === Pre-bind state information ===
    LOG: User = ian.uy
    LOG: DisplayName = Hello, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
     (Fully-specified)
    LOG: Appbase = file:///C:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/
    LOG: Initial PrivatePath = NULL
    LOG: Dynamic Base = NULL
    LOG: Cache Base = NULL
    LOG: AppName = NULL
    Calling assembly : HelloWorld, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
    ===
    LOG: This bind starts in default load context.
    LOG: No application configuration file found.
    LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
    LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
    LOG: Attempting download of new URL file:///C:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/Hello.DLL.
    LOG: Assembly download was successful. Attempting setup of file: C:\Users\ian.uy\Desktop\HelloWorld\HelloWorld\bin\Debug\Hello.dll
    LOG: Entering run-from-source setup phase.
    LOG: Assembly Name is: Hello, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    LOG: Binding succeeds. Returns assembly from C:\Users\ian.uy\Desktop\HelloWorld\HelloWorld\bin\Debug\Hello.dll.
    LOG: Assembly is loaded in default load context.
    

3 个答案:

答案 0 :(得分:2)

  

为什么会这样?

因为你已经指定了;)

  

如何让它无效?

  1. 右键单击 Solution Explorer
  2. 中的DLL
  3. 选择属性
  4. 选择使用特定版本
  5.   

    奖金问题:构建过程中会发生什么?外部依赖项的版本是否硬编码为主依赖项?

    除非您指定,否则不会。它默认是关闭的。精心设计的组件应该向后兼容,版本应该不重要。

答案 1 :(得分:1)

我面对同样的事情并试图查看msbuild日志:

msbuild /v:detailed /t:build

以下几行看起来很有趣:

  

Unified Dependency" Newtonsoft.Json,Version = 8.0.0.0,Culture = neutral,   公钥= 30ad4fe6b2a6aeed&#34 ;.         使用此版本而不是原始版本" 7.0.0.0"在" C:\ src \ BindingTest \ Lib1 \ bin \ Debug \ Lib1.dll"因为AutoUnify是   '真'

此外,如果在构建之后检出生成的app.config文件,您可能会看到app.config最初没有的自动绑定重定向。

所以我们观察到的行为与" automatic assembly unification"和" automatic binding redirection" msbuild进程。

以下是documentation关于AutoUnify参数的说明:

  

如果为true,则生成的依赖关系图将自动视为   如果有一个app.Config文件传入AppConfigFile   参数。此虚拟App.Config文件具有bindingRedirect条目   对于每个冲突的程序集集,使得最高版本   选择装配。这样做的结果是永远不会有   关于冲突组件的警告,因为每次冲突都会发生   已经解决了。

     

如果为true,则每次不同的重新映射都将导致高优先级   评论显示旧版本和新版本以及AutoUnify是否属实。

最后,如果你想观察"失败"你可以用以下参数调用msbuild:

msbuild /v:d /t:build /p:AutoUnifyAssemblyReferences=false;AutoGenerateBindingRedirects=false

答案 2 :(得分:0)

  

为了版本控制,运行时区分常规程序集和强名称程序集。版本检查仅对强名称程序集进行。

https://docs.microsoft.com/en-us/dotnet/framework/app-domains/assembly-versioning

因此,答案如下

  1. 因为程序集的名称不是很强
  2. 使程序集具有强名称
  3. 是的,引用程序集的版本是硬编码的。您可以使用反编译器(例如ILSpy)读取此信息来验证这一点