при наличии ключевого слова params компилятор немного переводит формальное объявление функции, а также фактический вызов функции.
Формальное объявление функции:
Под капотом IL будет переводиться по существу так же, как
public void Print<T>(T[] array);
За исключением того, что при компиляции фактический вызов функции будет проверен на трансляцию синтаксиса. Значение
a.Print("string1", "string2");
Получает тот же код IL, что и
a.Print(new string[]{"string1", "string2"});
Именно поэтому строки 2 и 3 имеют одинаковый выход, потому что под капотом они были переведены на точно такой же IL.
Вопрос о том, почему в строке 3 не выводится «T», заключается в том, что компилятор .NET всегда будет пытаться найти наилучшее перегруженное соответствие, и поэтому обе строки 2 и 3 будут вызываться для версии T [] вместо простого T.