Tout d'abord, laissez-moi juste dire que Jon réponse est bonne. C'est l'un des bien poilue parties de la spécification, si bon sur Jon pour plonger dedans la tête la première.
Deuxièmement, permettez-moi de dire que cette ligne:
Une conversion implicite existe à partir d'une méthode de groupe pour un compatible type délégué
(emphase ajoutée) est profondément trompeuse et malheureux. Je vais avoir une conversation avec Mads sur d'obtenir le mot "compatible" supprimé ici.
La raison pour cela est trompeur et malheureux, c'est parce qu'on dirait que c'est appeler à l'article 15.2, "Délégué de compatibilité". La Section 15.2 décrit la compatibilité de la relation entre les méthodes et les types délégués, mais c'est une question de la convertibilité de la méthode des groupes et des types délégués, ce qui est différent.
Maintenant que nous avons obtenu que sur le chemin, nous pouvons marcher à travers la section 6.6 de la spécification et de voir ce que nous obtenons.
Faire de résolution de surcharge, nous devons d'abord déterminer les surcharges sont applicables candidats. Un candidat est applicable que si tous les arguments sont implicitement convertible dans le paramètre formel types. Considérer cette version simplifiée de votre programme:
class Program
{
delegate void D1();
delegate string D2();
static string X() { return null; }
static void Y(D1 d1) {}
static void Y(D2 d2) {}
static void Main()
{
Y(X);
}
}
Donc, nous allons aller ligne par ligne.
Une conversion implicite existe à partir d'une méthode de groupe compatible type de délégué.
J'ai déjà discuté de la façon dont le mot "compatible" est malheureux ici. Aller de l'avant. Nous nous demandons quand on fait de la résolution de surcharge sur Y(X) méthode de groupe X convertir en D1? Est-il convertir de D2?
Étant donné un délégué de type D et un
l'expression de E qui est classé comme un
méthode de groupe, une conversion implicite
il existe de E à D si E contient au
moins une méthode qui s'applique [...] à une
liste d'arguments construits par l'utilisation de
les types de paramètres et les modificateurs de
D, comme décrit ci-après.
So far So good. X peut contenir une méthode qui est applicable avec l'argument des listes de D1 ou D2.
Le moment de la compilation de l'application d'une conversion à partir d'une méthode de groupe E à un délégué de type D est décrite ci-après.
Cette ligne n'a pas vraiment dire quelque chose d'intéressant.
Veuillez noter que l'existence d'une conversion implicite de E à D ne garantit pas que le moment de la compilation de l'application de la conversion réussira sans erreur.
Cette ligne est fascinant. Cela signifie qu'il y a des conversions implicites qui existent, mais qui sont susceptibles d'être transformé en erreurs! C'est bizarre ce que la règle de C#. Pour m'égare un moment, voici un exemple:
void Q(Expression<Func<string>> f){}
string M(int x) { ... }
...
int y = 123;
Q(()=>M(y++));
Une opération d'incrémentation est illégal dans une arborescence d'expression. Cependant, le lambda est toujours convertible à l'expression type d'arbre, même si la conversion est jamais utilisé, c'est une erreur! Le principe ici est que nous pourrions vouloir changer les règles de ce qui peut aller dans une arborescence d'expression plus tard; la modification de ces règles ne devraient pas changer le type de système de règles. Nous voulons vous forcer à faire de vos programmes sans ambiguïté maintenant, de sorte que lorsque nous changer les règles pour les arbres d'expression dans l'avenir de faire de leur mieux, à nous de ne pas introduire de rupture des changements dans la résolution de surcharge.
De toute façon, c'est un autre exemple de cette sorte de bizarre à la règle. Une conversion peut exister pour les fins de la résolution de surcharge, mais être une erreur d'utiliser effectivement. Bien que, en fait, ce n'est pas exactement la situation dans laquelle nous sommes ici.
Aller de l'avant:
Une seule méthode M est sélectionné correspondant à une invocation de méthode de la forme E(A) [...] La liste des arguments est une liste d'expressions, chaque classés en tant que variable [...] du paramètre correspondant dans le système-paramètres-liste de D.
OK. Donc, nous faisons de la résolution de surcharge sur X par rapport à D1. Le paramètre formel de la liste de D1 est vide, donc nous n'résolution de surcharge sur X() et de la joie, nous trouvons une méthode "chaîne X()" qui fonctionne. De même, le paramètre formel de la liste de D2 est vide. Encore une fois, nous constatons que la "chaîne X()" est une méthode qui fonctionne ici aussi.
Ici, le principe est que la détermination de la méthode de groupe de la convertibilité nécessite la sélection d'une méthode à partir d'une méthode de groupe à l'aide de la résolution de surcharge, et la résolution de surcharge ne considère pas les types de retour.
Si l'algorithme de [...] produit une erreur, une erreur de compilation se produit. Sinon, l'algorithme produit une meilleure méthode de M avoir le même nombre de paramètres que D et la conversion est réputée exister.
Il n'y a qu'une seule méthode dans la méthode du groupe de X, de sorte qu'il doit être le meilleur. Nous avons prouvé avec succès que la conversion existe de X à D1 et à partir de X à D2.
Maintenant, est-ce la ligne est-il pertinent?
La méthode sélectionnée M doit être compatible avec le délégué de type D, ou sinon, une erreur de compilation se produit.
En fait, non, pas dans ce programme. Nous n'avons jamais aller aussi loin que l'activation de cette ligne. Car, rappelons-le, ce que nous faisons ici est d'essayer de faire de la résolution de surcharge sur Y(X). Nous avons deux candidats Y(D1) et Y(D2). Les deux sont applicables. Qui est mieux? Nulle part dans le cahier des charges ne nous décrivons betterness entre ces deux conversions possibles.
Maintenant, on pourrait certainement faire valoir que la conversion est meilleur que celui qui produit une erreur. Ce serait alors effectivement dire que, dans ce cas, la résolution de surcharge NE tient pas compte des types de retour, ce qui est quelque chose que nous voulons éviter. La question est alors, le principe est le meilleur: (1) maintenir l'invariant que la résolution de surcharge ne considère pas les types de retour, ou (2) essayez de choisir un de conversion, nous le savons, le travail de plus d'un, nous le savons, non?
C'est un appel de jugement. Avec les lambdas, nous faire considérer le type de retour dans ces sortes de conversions, dans la section 7.4.3.3:
E est une fonction anonyme, T1 et T2
sont des types délégués ou de l'expression de l'arbre
les types des paramètres sont identiques listes,
une déduit le type de retour de X existe pour l'E
dans le contexte de la liste des paramètres,
et l'une des opérations suivantes:
T1 a un type de retour Y1, et T2 a un type de retour Y2, et de la conversion
de X à Y1 est mieux que le
la conversion de X Y2
T1 a un type de retour Y, et T2 est nulle retour
Il est regrettable que la méthode du groupe de conversions et de lambda conversions sont contradictoires dans ce domaine. Cependant, je peux vivre avec ça.
De toute façon, nous n'avons pas de "betterness" la règle pour déterminer la conversion est mieux, X D1 X D2. Par conséquent, nous donnons une erreur d'ambiguïté sur la résolution de Y(X).