问题源于在.NET Framework 4.6.2项目中使用NuGet包Microsoft.CodeAnalysis 2.0.0。
Microsoft.CodeAnalysis.dll
引用了System.Threading.Tasks, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
但是,这个组件无处可寻。
System.Threading.Tasks
NuGet包中不包含.NET 4.6.2的程序集,GAC仅包含此程序集的4.0.0.0版(后者仅包含类型转发器)。
但是尽管如此,一切都在运行时运行,实际上加载的程序集实际上是System.Threading.Tasks, Version=4.0.0.0
。
我的项目的app.config
也没有包含此程序集的绑定重定向。那么CLR如何将其解析为System.Threading.Tasks
的4.0.0.0版本?
尝试在Reflection-Only上下文中加载程序集时会出现问题,我们必须自己提供程序集解析处理程序,因为请求的程序集无处可寻,并且没有绑定重定向或任何暗示我们应该实际上加载的版本低于请求的程序集。
有人建议这是 retargetable 程序集。查看帖子here,它表明元数据应包含以下内容:
.assembly extern retargetable mscorlib
{
...
}
但是当我在ILdasm中查看Microsoft.CodeAnalysis.dll
时,我找不到任何可重新定位的内容。参考文献如下:
.assembly extern System.Threading.Tasks
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 4:0:10:0
}
可能是ILdasm隐藏了一些东西吗?
如果我尝试以下方法:
Assembly codeAnalysisAssembly =
Assembly.ReflectionOnlyLoadFrom("Microsoft.CodeAnalysis.dll");
foreach (var reference in codeAnalysisAssembly.GetReferencedAssemblies())
{
Console.WriteLine(reference.FullName);
}
返回的任何程序集名称都不包含任何引用“可重定向”程序集的信息(我可以找到)。
然而,运行时解析程序集在这里似乎不适用于仅反射上下文:
// This call succeeds and prints: System.Threading.Tasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Console.WriteLine(Assembly.Load("System.Threading.Tasks, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").FullName);
// This call throws an exception saying it cannot find the requested assembly.
Console.WriteLine(Assembly.ReflectionOnlyLoad("System.Threading.Tasks, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").FullName);
如果事实上,似乎Assembly.Load()
也会愉快地加载4.0.0.0
版本的System
程序集,无论我们请求哪个版本,只要major.minor部分版本等于4.0
。这里有一些有效的出版商政策吗?
Assembly.Load
时,CLR使用什么机制来“忽略”所请求的系统程序集的版本?AppDomain.ReflectionOnlyAssemblyResolve
时是否可以为Assembly.ReflectionOnlyLoad()
实现模仿此行为的处理程序?至少不使用原生Fusion-API?如果是这样,应该怎么做?