2016-06-16 3 views
2

J'ai été surpris aujourd'hui par la façon dont la résolution de la méthode fonctionne.Résolution de méthode C# avec inférence générique et de type

est ici le code comme exemple:

class Program 
{ 
    static class Mapper<TSource, TTarget> 
    { 
     public static void Map<TMember>(Expression<Func<TSource, TMember>> source, Expression<Func<TTarget, TMember>> target) 
     { 
      Console.WriteLine("A"); 
     } 

     public static void Map<TMember, TSourceCollection>(Expression<Func<TSource, TSourceCollection>> source, Expression<Func<TTarget, TMember[]>> target) 
      where TSourceCollection : IEnumerable<TMember> 
     { 
      Console.WriteLine("B"); 
     } 
    } 

    class A 
    { 
     public byte[] prop { get; set; } 
    } 

    class B 
    { 
     public byte[] prop { get; set; } 
    } 

    static void Main(string[] args) 
    { 
     Mapper<A, B>.Map(x => x.prop, x => x.prop); 
    } 
} 

Comme vous le voyez la méthode carte a deux surcharges, un lorsque le type de propriétés sont les mêmes, et un lorsque la propriété source est un dénombrable et la propriété right est un tableau.

Ensuite, quand j'appelle la méthode avec un tableau des deux côtés, il appelle la deuxième surcharge, mais comme les types sont exactement les mêmes, je m'attendais à ce que la première surcharge soit appelée. Je pensais que la première surcharge aurait un meilleur score car elle dépend de moins d'arguments génériques que la seconde, et elle correspond mieux aux types d'arguments que je passe à la méthode. Est-ce que quelqu'un peut expliquer pourquoi le compilateur choisit d'appeler la deuxième surcharge au lieu de la première s'il vous plaît?

Merci.

+0

Vous appelez le mappeur avec une classe A et B, qui ne sont pas des tableaux. Ils ont tous deux une propriété qui est un tableau d'octets, mais ils ne sont pas du même type. – Glubus

+0

Changez le byte [] en int et le premier est utilisé. Donc je suppose que c'est parce qu'un tableau d'octets est un IEnumerable. – user743414

+0

Merci, mais la résolution devrait se produire sur TMember, pas TSource ou TTarget. Le TSource et TTarget sont différents par nature. –

Répondre

1

La résolution de surcharge est compliquée et vous pouvez lire la spécification pour comprendre pourquoi. Une chose dont je suis sûr est cependant le fait qu'il ne considère pas la nécessité de spécifier des paramètres moins génériques quand on considère quelle surcharge est meilleure (bien que cela prendra non générique sur générique mais quand les deux sont génériques il les considère égaux).

Lorsque vous observez les surcharges, vous pouvez choisir entre elles sont toutes égales indépendamment de si le second paramètre est TMember ou TMember[]. La spécification parle beaucoup de choisir le membre le plus spécifique et je ne peux pas déterminer quelle partie est réellement applicable ici (il y a beaucoup d'endroits où il est question de préférer X sur Y quand X est plus spécifique). J'aurais pensé que c'était soit la section 7.6.5.1 (de la spécification C# 5) qui est là où elle construit une liste de candidats ou la section 7.5.3 où elle traite de la résolution de surcharge. Cependant, le premier ne semble exclure ni l'une ni l'autre des méthodes de surcharge et le dernier à ma lecture ne traite que des paramètres après que les génériques ont été substitués et à quel point ils sont identiques. Il se peut qu'il y ait un autre endroit dans la spécification qui traite de cela (par exemple quand il déduit les arguments de type). En termes laineux, je crois que le compilateur considère que TMember[] est plus spécifique que TMember. Cela peut être largement considéré comme vrai parce que TMember acceptera plus de choses que TMember [], donc TMember[] est plus spécifique.

+0

Merci pour la bonne explication, cela a du sens maintenant. –

1

La correspondance de la première méthode TMember et de la seconde méthode TSourceCollection est de valeur égale pour tout type qui satisfait à la condition where TSourceCollection : IEnumerable<TMember>. Le type TMember[] est un type de correspondance plus détaillé pour byte[] par rapport à TMember. Donc, cela devrait être le point où la deuxième méthode obtient de meilleurs résultats que la première. Par conséquent, ce «meilleur» match dépasse le fait que la deuxième méthode a des paramètres plus génériques.