2010-09-22 12 views
11

J'ai un type générique:Pourquoi ce code se plaindre de "l'arité de la définition de type générique"?

class DictionaryComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>> 

Et une méthode de fabrication qui (devrait) créer une instance de cette classe pour un type donné dictionnaire.

private static IEqualityComparer<T> CreateDictionaryComparer<T>() 
    { 
     Type def = typeof(DictionaryComparer<,>); 
     Debug.Assert(typeof(T).IsGenericType); 
     Debug.Assert(typeof(T).GetGenericArguments().Length == 2); 

     Type t = def.MakeGenericType(typeof(T).GetGenericArguments()); 

     return (IEqualityComparer<T>)Activator.CreateInstance(t); 
    } 

Suppression de tous les éléments superflus - même ce code lève la même exception.

private static object CreateDictionaryComparer() 
{ 
    Type def = typeof(DictionaryComparer<,>); 

    Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) }); 

    return Activator.CreateInstance(t); 
} 

Le Affirme passe donc je sais que T est générique et a deux arguments génériques. La ligne avec MakeGenericType cependant excepte avec:

Le nombre d'arguments génériques fournis ne correspond pas à l'arité de la définition de type générique.

Nom du paramètre: instanciation

je l'ai fait ce genre de chose dans le passé et pour la vie de moi ne peut pas comprendre pourquoi cela ne fonctionne pas dans ce cas. (plus je devais Google arity).

+0

Que transmettez-vous comme 'T' à' CreateDictionaryComparer'? J'ai essayé de passer 'CreateDictionaryComparer >()' et cela fonctionne très bien pour moi (en utilisant la version 1.9.1.0 du compilateur C# Mono). –

+0

J'avais DictionaryComparer comme une classe interne à celui qui est lui-même générique. Pensez que cela a détruit les travaux. – dkackman

+0

Juste par curiosité, pourriez-vous fournir l'échantillon complet (échouer) afin que je puisse l'essayer sur mon compilateur? –

Répondre

13

Compris. J'ai DictionaryComparer déclaré comme classe interne. Je peux seulement supposer que MakeGenericType voulait faire un Query<T>.DictionaryComparer<string,object> et n'a pas été fourni T.

Code défaut

class Program 
{ 
    static void Main(string[] args) 
    { 
     var q = new Query<int>(); 
     q.CreateError(); 
    } 
} 

public class Query<TSource> 
{ 
    public Query() 
    {  
    } 

    public object CreateError() 
    { 
     Type def = typeof(DictionaryComparer<,>); 

     Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) }); 

     return Activator.CreateInstance(t); 
    } 

    class DictionaryComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>> 
    { 
     public DictionaryComparer() 
     { 
     } 

     public bool Equals(IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y) 
     { 
      if (x.Count != y.Count) 
       return false; 

      return GetHashCode(x) == GetHashCode(y); 
     } 

     public int GetHashCode(IDictionary<TKey, TValue> obj) 
     { 
      int hash = 0; 
      unchecked 
      { 
       foreach (KeyValuePair<TKey, TValue> pair in obj) 
       { 
        int key = pair.Key.GetHashCode(); 
        int value = pair.Value != null ? pair.Value.GetHashCode() : 0; 
        hash ^= key^value; 
       } 
      } 
      return hash; 
     } 
    } 
} 
+0

Juste par curiosité, pourriez-vous fournir l'échantillon complet (échouer) afin que je puisse l'essayer sur mon compilateur? –

+0

Lemme voir si je peux enlever des choses sans rapport à un exemple compilable – dkackman

+0

Merci! Déplacer 'DictionaryComparer ' en dehors de la classe de conteneur générique 'Query ' résout le problème. J'ai expérimenté et vous pouvez nicher 'DictionaryComparer ', mais pas dans une autre classe générique. Je voulais aussi m'assurer que mon compilateur et mon environnement d'exécution se comportaient comme les vôtres. –

1

CLR crée une structure de données interne pour chaque type dans l'utilisation par une structure de données application.These sont appelés objets de type. Un type avec des paramètres de type générique est appelé un type ouvert, et CLR ne permet pas de construire une instance de type ouvert (similaire à la façon dont le CLR empêche la construction d'une instance d'un type d'interface).

Modifier Type t = def.MakeGenericType (nouveau type [] {typeof (chaîne), typeof (objet)});

Type t = def.MakeGenericType (nouveau type [] {typeof (TSource), typeof (chaîne), typeof (objet)});