Überlasten, generische Typinferenz und das ‚params‘ Schlüsselwort
-
10-07-2019 - |
Frage
Ich habe gerade bemerkt ein seltsames Verhalten mit Überladungsauflösung.
Nehmen wir an, ich die folgende Methode haben:
public static void DoSomething<T>(IEnumerable<T> items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(IEnumerable<T> items)");
}
Nun, ich weiß, dass diese Methode wird oft mit einer kleinen Anzahl von expliziten Argumenten aufgerufen werden, so der Einfachheit halber füge ich diese Überlastung:
public static void DoSomething<T>(params T[] items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(params T[] items)");
}
Jetzt versuche ich, diese Methoden zu nennen:
var items = new List<string> { "foo", "bar" };
DoSomething(items);
DoSomething("foo", "bar");
Aber in beiden Fällen ist die Überlastung mit params
genannt. Ich würde die IEnumerable<T>
Überlastung zu erwarten im Fall eines List<T>
genannt werden, weil es eine bessere Übereinstimmung (zumindest für mich) scheint.
Ist dieses Verhalten normal? Könnte jemand erklären? Ich konnte keine klaren Informationen über die in MSDN-Dokumentation finden ... Was die Überladungsauflösung Regeln hier beteiligt sind?
Lösung
Abschnitt 7.4.3 der C # 3.0-Spezifikation ist das entsprechende Bit hier. Grundsätzlich ist der Parameter-Array wird erweitert, so dass Sie vergleichen:
public static void DoSomething<T>(T item)
und
public static void DoSomething<T>(IEnumerable<T> item)
Die T
für das erste Spiel wird gefolgert werden List<string>
und die T
für das zweite Spiel wird gefolgert string
werden.
List<string>
ist zu List<string>
- Jetzt die Konvertierungen für Argument Parametertyp beteiligt betrachten im zweiten ist es List<string>
IEnumerable<string>
. Die erste Umwandlung ist besser als die zweite durch die Regeln in 7.4.3.4.
Das eingängig Bit ist die Typinferenz. Wenn Sie, dass aus der Gleichung nehmen, wird es funktionieren, wie Sie es erwarten:
var items = new List<string> { "foo", "bar" };
DoSomething<string>(items);
DoSomething<string>("foo", "bar");
An diesem Punkt gibt es nur einen gültigen Funktionselement in jedem Aufruf.