2009-08-07 7 views
2

Est-ce que j'ai trébuché sur le comportement défini par l'implémentation?Types génériques imbriqués CLI et méthodes génériques

Voici le contexte:

public class GenericClass<T> 
{ 
    public class NestedGenericClass<U> 
    { 
     public void GenericMethod<K>() 
     { 
     } 
    } 
} 

est ici le comportement. Ce test unitaire passe comme écrit. Mes vraies questions sont listées comme le commentaire avant le comportement "farfelu" (comme il me semble maintenant).

[TestMethod] 
public void TestNestedGenericMethod() 
{ 
    Type openType = typeof(GenericClass<>.NestedGenericClass<>); 
    Type closedType = typeof(GenericClass<bool>.NestedGenericClass<int>); 
    /* Note there is absolutely no representation of the following as a [unique] type, via the 
    * typeof operator or the Reflection API, even though the metadata TypeSpec signature 
    * should in theory be able to reference it. This is the original reason I wrote these 
    * tests. 
    * Type partiallyOpenType = typeof(GenericClass<bool>.NestedGenericClass<>); 
    */ 

    MethodInfo openTypeOpenMethod = openType.GetMethod("GenericMethod"); 
    MethodInfo closedTypeOpenMethod = closedType.GetMethod("GenericMethod"); 
    MethodInfo closedTypeClosedMethod = closedTypeOpenMethod.MakeGenericMethod(typeof(long)); 

    Assert.IsNotNull(openTypeOpenMethod); 
    Assert.IsNotNull(closedTypeOpenMethod); 
    Assert.IsNotNull(closedTypeClosedMethod); 

    Assert.AreNotSame(openTypeOpenMethod, closedTypeOpenMethod); 
    Assert.AreNotSame(openTypeOpenMethod, closedTypeClosedMethod); 
    Assert.AreNotSame(closedTypeOpenMethod, closedTypeClosedMethod); 

    /* What on earth?! 
    * 1. Is the following covered in the CLI spec and/or is it implementation-defined? 
    * 2. Is there any potential use of this behavior (inside the runtime itself OR outside)? 
    * 3. Will I ever hit a MethodDefSig (§23.2.1)/MethodRefSig (§23.2.2)/MethodSpecSig (§23.2.15) that resolves to this? 
    */ 
    MethodInfo openTypeClosedMethod = openTypeOpenMethod.MakeGenericMethod(typeof(long)); 
    Assert.IsNotNull(openTypeClosedMethod); 
    Assert.AreNotSame(openTypeClosedMethod, openTypeOpenMethod); 
    Assert.AreNotSame(openTypeClosedMethod, closedTypeOpenMethod); 
    Assert.AreNotSame(openTypeClosedMethod, closedTypeClosedMethod); 

    Assert.AreSame(closedTypeOpenMethod, closedTypeClosedMethod.GetGenericMethodDefinition()); 
    Assert.AreSame(openTypeOpenMethod, openTypeClosedMethod.GetGenericMethodDefinition()); 
} 

Répondre

0

Ce n'est pas si étrange:

//void GenericClass<>.NestedGenericClass<>.GenericMethod<Int64>() 
openTypeClosedMethod.ContainsGenericParameters = true 
openTypeClosedMethod.IsGenericMethodDefinition = false 

//void GenericClass<>.NestedGenericClass<>.GenericMethod<K>() 
openTypeOpenMethod.ContainsGenericParameters = true 
openTypeOpenMethod.IsGenericMethodDefinition = true 

//void GenericClass<bool>.NestedGenericClass<int>.GenericMethod<K>() 
closedTypeOpenMethod.ContainsGenericParameters = true 
closedTypeOpenMethod.IsGenericMethodDefinition = true 

//void GenericClass<bool>.NestedGenericClass<int>.GenericMethod<Int64>() 
closedTypeClosedMethod.ContainsGenericParameters = false 
closedTypeClosedMethod.IsGenericMethodDefinition = false 

MethodInfo closedGeneratedMethod = closedTypeClosedMethod.GetGenericMethodDefinition(); 
MethodInfo openGeneratedMethod = openTypeClosedMethod.GetGenericMethodDefinition(); 

//void GenericClass<bool>.NestedGenericClass<int>.GenericMethod<K>() 
closedGeneratedMethod.ContainsGenericParameters = true 
closedGeneratedMethod.IsGenericMethodDefinition = true 

//void GenericClass<>.NestedGenericClass<>.GenericMethod<K>() 
openGeneratedMethod.ContainsGenericParameters = true 
openGeneratedMethod.IsGenericMethodDefinition = true 

Il suffit de comparer toutes les combinaisons de Affirme.

P.S. Vous avez manqué

Assert.AreNotSame(closedTypeOpenMethod, openTypeOpenMethod); 
+0

1) Je n'ai pas manqué ce cas (ses paramètres sont inversés mais je l'ai). 2) Aucun de ces contrôles sont remarquables après ceux dans mon poste, mais je vais les ajouter plus car ils sont importants pour l'API. 3) Vous n'avez répondu à aucune de mes trois questions, qui se réfèrent toutes au fait que l'implémentation .NET Framework d'ECMA-335 permet la méthode générique fermée dans un type générique ouvert. Je travaille sur ma propre mise en œuvre de la norme pour le plaisir, et j'essaie de comprendre si je dois soutenir ce cas ou non. :) –

+0

D'accord, désolé pour le poste «insignifiant». La CLI interdit explicitement les méthodes génériques fermées dans un type générique ouvert. Il définit les relations entre une méthode générique et son type déclarant, ainsi que les types génériques imbriqués. La CLI interdit seulement les types partiellement construits, et instanciant les types ouverts, donc je suppose que la méthode ne serait pas très utile, au moins pour les méthodes par exemple. Quant à MethodDefSig et d'autres, pourquoi n'essayez-vous pas de l'émettre dans un assemblage dynamique et de l'analyser à partir du disque? –