Вопрос возникает из-за использования пакета NuGet Microsoft.CodeAnalysis 2.0.0 в проект .NET Framework 4.6.2.
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 разрешает его в версию 4.0.0.0 System.Threading.Tasks?
Проблема возникает при попытке загрузить сборки в контексте только для отражения, где мы должны сами предоставить обработчик разрешения сборки, поскольку запрошенная сборка нигде не найдена, и нет никаких перенаправлений привязки или чего-либо, намекающего на то, что мы должны фактически загрузить сборку. более низкая версия, чем запрошенная сборка.
Обновлять
Было высказано предположение, что это перенацеливаемая сборка. Глядя на сообщение здесь, предполагается, что метаданные должны содержать что-то вроде следующего:
.assembly extern retargetable mscorlib
{
...
}
Но когда я смотрю на Microsoft.CodeAnalysis.dll в ILdasm, я не могу найти в нем упоминания о том, что что-то может быть перенацелено. Ссылка выглядит так:
.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, независимо от того, какую версию мы запрашиваем, если основная.младшая часть версии равна 4.0. Возможно, здесь действует какая-то политика издателя?
Конкретные вопросы
- Какой механизм CLR использует для «игнорирования» версий запрошенных системных сборок при использовании
Assembly.Load? - Можно ли реализовать обработчик для
AppDomain.ReflectionOnlyAssemblyResolve, который имитировал бы это поведение при использованииAssembly.ReflectionOnlyLoad()? Хотя бы не прибегая к нативному Fusion-API? И если да, то как это нужно сделать?