2016-10-31 3 views
3

Prenons l'exemple suivant:L'inférence de type est-elle effectuée de droite à gauche?

public class Person 
{ 
    public int Age { get; set; } 
} 

public class Builder<TSource> 
{ 
    public Builder<TSource> WithValue<TValue>(Func<TSource, TValue>, TValue value) 
    { 
     // ... 
    } 
} 

Ces deux lignes fonctionnent et fonctionnent très bien:

Builder<Person> builder = new Builder<Person>(); 
builder.WithValue(p => p.Age, 20); 

Mais même ces:

Builder<Person> builder = new Builder<Person>(); 
object age = "20";        // <-- string value 
builder.WithValue(p => p.Age, age); 

L'inférence de type ne fonctionne pas la façon dont je attendez-vous à travailler sur le dernier exemple.

Si je spécifie une expression p => p.Age, qui est Func<Person, int>, je me attends le deuxième argument à contraindre à un type int. Pourtant, je suis capable de passer un object très bien.

Je suppose que c'est parce que l'inférence de type est faite de droite à gauche. C'est-à-dire que l'argument TValue est déduit comme object et que mon expression Func<TSource, TValue> est contrainte à Func<Person, object>, ce que p => p.Age satisfait très bien.

Mon hypothèse est-elle correcte?

Si oui, pourquoi l'inférence de type est-elle faite de cette façon? Je le trouve plus naturel de gauche à droite.

Répondre

5

Ce n'est pas du tout tributaire de l'ordre. Le paramètre p => p.Age ajoute la contrainte que quel que soit TValue doit être un type qui peut stocker un int. Cela peut être int ou tout type dont il hérite, par exemple, object. Lorsque vous passez dans age vous dites que TValue doit être un type qui peut stocker un object. Il choisira ensuite le type le plus dérivé qui répond à toutes ces contraintes, qui dans ce cas est object. La même chose se produirait si vous changiez l'ordre des paramètres.

+0

Le type le plus dérivé n'est-il pas 'int'? –

+0

@MatiasCicero Le type 'int' ne répond pas aux deux contraintes; il ne répond qu'à l'une des deux contraintes, puisque vous ne pouvez pas stocker un 'object' dans une variable de type' int'. – Servy

+0

Je pense que je comprends maintenant. Merci pour la réponse rapide! –

1

Ce n'est ni de gauche à droite, ni de droite à gauche. L'inférence de type prend l'information de type disponible dans la situation donnée, et essaye de déterminer quel type peut être substitué afin qu'il soit compatible avec toutes les expressions respectives. Ceci est généralement satisfait par l'ancêtre commun le plus proche. Dans votre cas, int et object ont object comme ancêtre commun le plus proche. Cependant, en général, la résolution peut être un peu plus compliquée en raison des interfaces.