web-dev-qa-db-fra.com

Pourquoi GetType () ne trouve-t-il pas les types lorsqu'ils sont appelés via un délégué de groupe de méthodes?

Nous avons un programme très simple invoquant le Type.GetType méthode statique. Les deux exemples doivent renvoyer une instance de type valide. Seul le second l'est réellement. Il semble que quelque chose de bizarre se produise avec l'analyse de pile utilisée par GetType, mais quel est exactement le problème ici? Est-ce un bug ou une fonctionnalité obscure?

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));
    }
}

Fonctionnement:

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

C'est vraiment intéressant. C'est un mélange du comportement de Type.GetType(string) en termes d'assembly appelant et de fonctionnement des conversions de groupes de méthodes.

Tout d’abord, la documentation Type.GetType inclut ceci:

Si typeName inclut l'espace de nom mais pas le nom de l'assembly, cette méthode recherche uniquement l'assembly et l'objet Mscorlib.dll de l'objet appelant, dans cet ordre.

Lors de votre premier appel, vous transmettez un délégué qui appelle Type.GetType ... mais il n'est pas particulièrement appelé depuis votre assemblée. C'est effectivement appelé directement à partir de la méthode Select dans LINQ ... si vous avez regardé le tracé de la pile à l'intérieur de Type.GetType, vous verriez Select comme appelant direct, je crois.

Dans votre deuxième appel, vous passez une fermeture qui appelle Type.GetType, Et cet appel est dans votre assemblée.

C'est pourquoi il trouve le type dans le second cas mais pas dans le premier. Ceci est ensuite validé en spécifiant un type qui est dans l’assemblage LINQ:

var fullName = typeof(Enumerable).FullName;

Ensuite, les résultats sont inversés:

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

Si vous spécifiez quelque chose dans mscorlib (par exemple, typeof(string).FullName), les deux approches fonctionnent:

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

Pour contourner cette bizarrerie lorsque vous recherchez votre classe, en utilisant toujours un groupe de méthodes, vous devez simplement fournir le nom qualifié à l’Assemblée:

var fullName = typeof(TestClass).AssemblyQualifiedName;
165
Jon Skeet