Почему GetType() не может найти типы при вызове через делегат группы методов?

У нас очень простая программа, вызывающая статический метод Type.GetType. Оба примера должны возвращать действительный экземпляр типа. На самом деле это только вторая. Похоже, что что-то странное происходит со сканированием стека, используемым GetType, но что конкретно здесь проблема? Это ошибка или какая-то неясная особенность?

public class TestClass { }

class Program
{
    static void Main(string[] args)
    {
        var fullName = typeof(TestClass).FullName;
        Console.WriteLine("Full name: {0}", fullName);

        new[] { fullName }.Select(Type.GetType).ToList().ForEach(t => Console.WriteLine("Method group: '{0}'", t));
        new[] { fullName }.Select(t => Type.GetType(t)).ToList().ForEach(t => Console.WriteLine("Closure: '{0}'", t));
    }
}

Продолжительность:

Full name: GetTypeBeingWeird.TestClass
Method group: ''
Closure: 'GetTypeBeingWeird.TestClass'

Ответ 1

Это действительно интересно. Это смесь поведения Type.GetType(string) в терминах вызывающей сборки и способов преобразования групп методов.

Во-первых, Type.GetType документация включает в себя следующее:

Если typeName включает пространство имен, но не имя сборки, этот метод выполняет поиск только сборки вызывающего объекта и Mscorlib.dll в этом порядке.

В вашем первом вызове вы передаете делегат, который вызывает Type.GetType... но его особо не вызывают из вашей сборки. Он эффективно вызван непосредственно из метода Select в LINQ... если вы посмотрели на трассировку стека из Type.GetType, вы бы увидели Select как прямой вызывающий.

Во втором вызове вы завершаете закрытие, которое вызывает Type.GetType, и этот вызов находится внутри вашей сборки.

Вот почему он находит тип во втором случае, но не первый. Это дополнительно подтверждается путем указания типа, который находится в сборке LINQ:

var fullName = typeof(Enumerable).FullName;

Затем результаты противоположны:

Full name: System.Linq.Enumerable
Method group: 'System.Linq.Enumerable'
Closure: ''

Если вы укажете что-то в mscorlib (например, typeof(string).FullName), то оба подхода работают:

Full name: System.String
Method group: 'System.String'
Closure: 'System.String'

Способ обойти эту странность при поиске вашего класса, все еще используя группу методов, заключается просто в том, чтобы вместо этого присвоить имя с помощью сборки:

var fullName = typeof(TestClass).AssemblyQualifiedName;