Ich habe diese Klasse
public class Overloaded
{
public void ComplexOverloadResolution(params string[] something)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
}
Wenn ich es so nenne:
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
Es schreibt Normal Winner
in die Konsole.
Aber wenn ich eine andere Methode hinzufüge:
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
Ich erhalte folgende Fehlermeldung:
Der Aufruf ist zwischen den folgenden Methoden oder Eigenschaften nicht eindeutig:> '
Overloaded.ComplexOverloadResolution(params string[])
' und 'Overloaded.ComplexOverloadResolution<string>(string)
'
Ich kann verstehen, dass das Hinzufügen einer Methode zu einer Aufrufmehrdeutigkeit führen kann, aber es ist eine Mehrdeutigkeit zwischen den beiden bereits vorhandenen Methoden (params string[])
und <string>(string)
! Es ist klar, dass keine der beiden an der Mehrdeutigkeit beteiligten Methoden die neu hinzugefügte Methode ist, da die erste ein Parameter und die zweite eine generische ist.
Ist das ein Fehler? Welcher Teil der Spezifikation besagt, dass dies der Fall sein sollte?
quelle
'Overloaded.ComplexOverloadResolution(string)'
bezieht sich auf die<string>(string)
Methode; Ich denke, es bezieht sich auf die(string, object)
Methode ohne Objekt geliefert.Antworten:
Ja.
Herzlichen Glückwunsch, Sie haben einen Fehler in der Überlastungsauflösung gefunden. Der Fehler wird in C # 4 und 5 reproduziert. es wird in der "Roslyn" -Version des semantischen Analysators nicht reproduziert. Ich habe das C # 5-Testteam informiert und hoffe, dass wir dies vor der endgültigen Veröffentlichung untersuchen und lösen können. (Wie immer keine Versprechen.)
Eine korrekte Analyse folgt. Die Kandidaten sind:
Kandidat Null ist offensichtlich nicht anwendbar, da er
string
nicht in konvertierbar iststring[]
. Das lässt drei.Von den dreien müssen wir eine einzigartige beste Methode bestimmen. Dazu vergleichen wir die drei verbleibenden Kandidaten paarweise. Es gibt drei solche Paare. Alle von ihnen haben identisch Parameterlisten, sobald wir die ausgelassenen optionalen Parameter entfernt haben. Dies bedeutet, dass wir zu der in Abschnitt 7.5.3.2 der Spezifikation beschriebenen erweiterten Tiebreaking-Runde gehen müssen.
Welches ist besser, 1 oder 2? Der relevante Tiebreaker ist, dass eine generische Methode immer schlechter ist als eine nicht generische Methode. 2 ist schlechter als 1. 2 kann also nicht der Gewinner sein.
Welches ist besser, 1 oder 3? Der relevante Tiebreaker ist: Eine Methode, die nur in ihrer erweiterten Form anwendbar ist, ist immer schlechter als eine Methode, die in ihrer normalen Form anwendbar ist. Daher ist 1 schlechter als 3. Also kann 1 nicht der Gewinner sein.
Welches ist besser, 2 oder 3? Der relevante Tiebreaker ist, dass eine generische Methode immer schlechter ist als eine nicht generische Methode. 2 ist schlechter als 3. 2 kann also nicht der Gewinner sein.
Um aus einer Reihe von mehreren Kandidaten ausgewählt zu werden, muss ein Kandidat (1) ungeschlagen sein, (2) mindestens einen anderen Kandidaten schlagen und (3) der eindeutige Kandidat sein, der die ersten beiden Eigenschaften hat. Kandidat drei wird von keinem anderen Kandidaten geschlagen und schlägt mindestens einen anderen Kandidaten; Es ist der einzige Kandidat mit dieser Eigenschaft. Daher ist Kandidat drei der einzigartig beste Kandidat . Es sollte gewinnen.
Der C # 4-Compiler versteht es nicht nur falsch, da Sie richtig bemerken, dass er eine bizarre Fehlermeldung meldet. Dass der Compiler die Analyse der Überlastungsauflösung falsch macht, ist ein wenig überraschend. Dass die Fehlermeldung falsch ist, ist völlig überraschend. Die Fehlerheuristik "mehrdeutige Methode" wählt grundsätzlich zwei beliebige Methoden aus dem Kandidatensatz aus, wenn keine beste Methode ermittelt werden kann. Es ist nicht sehr gut, die "echte" Mehrdeutigkeit zu finden, wenn es tatsächlich eine gibt.
Man könnte vernünftigerweise fragen, warum das so ist. Es ist ziemlich schwierig, zwei Methoden zu finden , die "eindeutig mehrdeutig" sind, da die Beziehung "Betterness" intransitiv ist . Es ist möglich, Situationen zu finden, in denen Kandidat 1 besser als 2, 2 besser als 3 und 3 besser als 1 ist. In solchen Situationen können wir es nicht besser machen, als zwei davon als "die mehrdeutigen" auszuwählen.
Ich möchte diese Heuristik für Roslyn verbessern, aber sie hat eine niedrige Priorität.
(Übung für den Leser: "Entwickeln Sie einen linearen Zeitalgorithmus, um das eindeutige beste Mitglied einer Menge von n Elementen zu identifizieren, bei denen die Betterness-Beziehung intransitiv ist", war eine der Fragen, die mir am Tag meines Interviews für dieses Team gestellt wurden ein sehr harter Algorithmus; probieren Sie es aus.)
Einer der Gründe, warum wir das Hinzufügen optionaler Argumente zu C # so lange zurückgedrängt haben, war die Anzahl der komplexen mehrdeutigen Situationen, die in den Überlastungsauflösungsalgorithmus eingeführt werden. anscheinend haben wir es nicht richtig verstanden.
Wenn Sie ein Connect-Problem eingeben möchten, um es zu verfolgen, können Sie dies gerne tun. Wenn Sie nur möchten, dass wir darauf aufmerksam gemacht werden, halten Sie es für erledigt. Ich werde nächstes Jahr mit dem Testen fortfahren.
Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben. Entschuldigung für den Fehler.
quelle
Abschnitt 7.5.3 (Überlastungsauflösung) sowie Abschnitte 7.4 (Mitgliedersuche) und 7.5.2 (Typinferenz).
Beachten Sie insbesondere Abschnitt 7.5.3.2 (besseres Funktionselement), in dem teilweise angegeben ist, dass "optionale Parameter ohne entsprechende Argumente aus der Parameterliste entfernt werden" und "Wenn M (p) eine nicht generische Methode ist und M (q) eine generische Methode, dann ist M (p) besser als M (q). "Ich verstehe diese Teile der Spezifikation jedoch nicht gründlich genug, um zu wissen, welche Teile der Spezifikation dieses Verhalten steuern, geschweige denn, um zu beurteilen, ob es konform ist.
quelle
Sie können diese Mehrdeutigkeit vermeiden, indem Sie in einigen Methoden den Namen des ersten Parameters ändern und den Parameter angeben, den Sie zuweisen möchten
so was :
quelle
Wenn Sie die
params
von Ihrer ersten Methode entfernen , würde dies nicht passieren.ComplexOverloadResolution(string)
Ihre erste und dritte Methode haben beide gültige Aufrufe , aber wenn Ihre erste Methode ist,public void ComplexOverloadResolution(string[] something)
gibt es keine Mehrdeutigkeit.Wenn Sie einen Wert für einen Parameter
object somethingElse = null
angeben, wird dieser zu einem optionalen Parameter und muss daher beim Aufrufen dieser Überladung nicht angegeben werden.Edit: Der Compiler macht hier ein paar verrückte Sachen. Wenn Sie Ihre dritte Methode nach der ersten in Code verschieben, wird sie korrekt gemeldet. Es scheint also, dass die ersten beiden Überladungen genommen und gemeldet werden, ohne nach der richtigen zu suchen.
Edit2: Neuer Befund. Wenn Sie eine der drei oben genannten Methoden entfernen, entsteht keine Mehrdeutigkeit zwischen den beiden. Es scheint also, dass der Konflikt nur auftritt, wenn drei Methoden vorhanden sind, unabhängig von der Reihenfolge.
quelle
Wenn du schreibst
oder einfach schreiben
wird es endet in das gleiche Verfahren , in Verfahren
Dies ist ein
params
Schlüsselwort für die Ursache , mit dem es am besten auch für den Fall übereinstimmt, dass kein Parameter angegeben wurdeWenn Sie versuchen, Ihre neue Methode wie diese hinzuzufügen
Diese Methode wird perfekt kompiliert und aufgerufen, da sie perfekt zu Ihrem Aufruf mit einem
string
Parameter passt . Dann viel stärkerparams string[] something
.Sie deklarieren die zweite Methode wie Sie
Compiler, springt in völliger Verwirrung zwischen der ersten Methode und dieser, hat gerade eine hinzugefügt. Weil es nicht weiß, welche Funktion er jetzt alle bei Ihrem Anruf haben soll
Wenn Sie den Zeichenfolgenparameter wie einen folgenden Code aus dem Aufruf entfernen, wird alles korrekt kompiliert und funktioniert wie zuvor
quelle
state
drei Funktionen hat, nicht einzelne oder einige, um genau zu sein. Tatsächlich reicht es aus, einen von ihnen zu kommentieren , um ein Problem zu lösen. Die beste Übereinstimmung zwischen den verfügbaren Funktionen ist die mitparams
, die zweite mit demgenerics
Parameter. Wenn wir die dritte hinzufügen, führt dies zu einer Verwirrung in einerset
der Funktionen. Ich denke, es ist höchstwahrscheinlich keine klare Fehlermeldung, die vom Compiler erzeugt wird.