Когда вы используете any dynamici c значения в качестве аргумента в вызове метода, метод динамически привязывается. Если вы используете типовой вывод generic c на всех (независимо от того, участвует ли в этом значение dynamici c), ограничения типа generi c не проверяются.
Вот немного более простая версия того, что вы видите:
using System;
class Test
{
static void Main()
{
dynamic d = 1;
// Compiles
M(d, 0);
// Doesn't compile - explicit type argument
M<int>(d, 0);
}
static void M<T>(object ignored, T value) where T : class
{
}
}
Компилятор выполнит некоторую проверку, но он относительно консервативен с точки зрения того, что он проверяет. По сути, если вы погружаетесь в сферу динамического связывания c, вы должны быть действительно осторожными и ожидать, что все может сделать не так много проверки типов, как вы думаете.
(Если я правильно помню, spe c довольно точно не говорит о том, сколько проверки выполняется для динамически связанных операций, так что вы можете потенциально оказаться в ситуации, когда он компилируется с некоторыми компиляторами, но не с другими.)