Как CLR удается разрешить более низкую версию запрошенной сборки без перенаправления привязки в app.config?

Вопрос возникает из-за использования пакета 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. Возможно, здесь действует какая-то политика издателя?

Конкретные вопросы

  1. Какой механизм CLR использует для «игнорирования» версий запрошенных системных сборок при использовании Assembly.Load?
  2. Можно ли реализовать обработчик для AppDomain.ReflectionOnlyAssemblyResolve, который имитировал бы это поведение при использовании Assembly.ReflectionOnlyLoad()? Хотя бы не прибегая к нативному Fusion-API? И если да, то как это нужно сделать?

person DeCaf    schedule 12.04.2017    source источник
comment
Это перенацеливаемая сборка. Довольно запутанная деталь, этот Q + A говорит об этом. В остальном принципиально не отличается от того, как CLR v4.0.30319 может загружать сборку, созданную для версии 2.0.50727 и, следовательно, зависящую, скажем, от версии 2.0.0.0 mscorlib.dll, переключаемой во время выполнения.   -  person Hans Passant    schedule 12.04.2017
comment
@HansPassant Это объясняет ... ну, во всяком случае, половину. Как мне вручную разрешить правильную сборку в случае контекста только для отражения? Есть ли какая-либо информация в сборке retargetable, указывающая, для какой версии она является перенацеливаемой, или что-то в этом роде?   -  person DeCaf    schedule 12.04.2017
comment
Вы задали только половину вопроса и не показали нам, какую проблему вы пытались решить. Пустая трата времени для вас и для нас, в этом нет никакого смысла. Вероятно, дубликат этого.   -  person Hans Passant    schedule 12.04.2017
comment
@HansPassant Вероятно, вы правы в том, что вопрос был не очень ясен. Извини за это. У меня не было намерения, чтобы мой комментарий выше был какой-либо формой жалобы. Я всегда ценю ваши идеи! Я обновил вопрос и попытался сделать его более конкретным. (Надеюсь, я не просто сделал это более неясным)   -  person DeCaf    schedule 12.04.2017