c # Methode mit unbegrenzten Parametern oder Methode mit einem Array oder einer Liste?

21

Ich habe kürzlich erfahren, dass Sie eine Methode mit unbegrenzten Parametern erstellen können, zum Beispiel:

SomeMethod(params int[] numbers);

Aber meine Frage ist, was ist der Unterschied zwischen dem und dem Erstellen einer Methode, die eine Liste oder ein Array empfängt?

SomeMethod(int[] numbers);
SomeMethod(List<int> numbers);

Vielleicht hat es einen Einfluss auf die Leistung? Ich verstehe oder sehe nicht ganz, auf welche Weise Sie die mit unbegrenzten Parametern bevorzugen würden.

Eine schnelle Suche auf Google hat nicht geholfen, ich hoffe, Sie konnten mir helfen.

Ricardo Sanchez Santos
quelle
Schauen Sie sich das an: stackoverflow.com/questions/434761/…
Mr.AF
Zusätzlich zu meiner Antwort unten, paramsauch erfordert die Art des Arguments ein Array zu sein. Wenn Sie eine andere Sammlung als ein Array verwenden müssen, ist es möglicherweise sinnvoller, paramsstattdessen ein Nichtargument anzugeben.
digitlworld
1
@digitlworld: Wenn Sie an diesem Thema interessiert sind, finden Sie weitere Informationen unter github.com/dotnet/csharplang/issues/179 .
Eric Lippert
Schauen Sie sich die Signatur und / oder Implementierung von an Console.Write.
3Dave

Antworten:

27

Was ist der Unterschied zwischen dem Erstellen einer Methode, die eine Liste oder ein Array empfängt?

Der Unterschied zwischen

void M(params int[] x)

und

void N(int[] x)

ist, dass M so genannt werden kann:

M(1, 2, 3)

oder so:

M(new int[] { 1, 2, 3 });

aber N darf nur auf die zweite Weise aufgerufen werden, nicht auf die erste .

Vielleicht hat es einen Einfluss auf die Leistung?

Die Auswirkung auf die Leistung besteht darin, dass unabhängig davon, ob Sie Mauf die erste oder die zweite Weise aufrufen, in beiden Fällen ein Array erstellt wird. Das Erstellen eines Arrays wirkt sich auf die Leistung aus, da es sowohl Zeit als auch Speicher benötigt. Denken Sie daran, dass die Auswirkungen auf die Leistung an den Leistungszielen gemessen werden sollten. Es ist unwahrscheinlich, dass die Kosten für die Erstellung eines zusätzlichen Arrays der entscheidende Faktor für Erfolg und Misserfolg auf dem Markt sind.

Ich verstehe oder sehe nicht ganz, auf welche Weise Sie die mit unbegrenzten Parametern bevorzugen würden.

Es ist rein und vollständig eine Annehmlichkeit für den Autor des Codes, der die Methode aufruft; es ist einfach kürzer und einfacher zu schreiben

M(1, 2, 3);

anstatt zu schreiben

M(new int[] { 1, 2, 3 });

Es werden nur ein paar Tastenanschläge auf der Anruferseite gespeichert. Das ist alles.

Einige Fragen, die Sie nicht gestellt haben, die Sie aber vielleicht gerne beantworten möchten:

Wie heißt diese Funktion?

Methoden, mit denen eine variable Anzahl von Argumenten auf der Aufruferseite übergeben werden kann, werden als variadic bezeichnet . Mit Params-Methoden implementiert C # verschiedene Methoden.

Wie funktioniert die Überlastungsauflösung mit einer variadischen Methode?

Bei einem Problem mit der Überlastungsauflösung berücksichtigt C # sowohl das "normale" als auch das "erweiterte" Formular, und das "normale" Formular gewinnt immer, wenn beide zutreffen. Betrachten Sie zum Beispiel Folgendes:

void P(params object[] x){}

und wir haben einen Anruf

P(null);

Es gibt zwei anwendbare Möglichkeiten. In "normaler" Form rufen wir Peine Nullreferenz für das Array auf und übergeben sie. In "erweiterter" Form nennen wir P(new object[] { null }). In diesem Fall gewinnt die normale Form. Wenn wir einen Anruf hatten, P(null, null)ist das normale Formular nicht anwendbar und das erweiterte Formular gewinnt standardmäßig.

Herausforderung : Nehmen wir an, wir haben var s = new[] { "hello" };einen Anruf P(s);. Beschreiben Sie, was an der Anrufstelle passiert und warum. Sie könnten überrascht sein!

Herausforderung : Angenommen, wir haben beide void P(object x){}und void P(params object[] x){}. Was macht P(null)und warum?

Herausforderung : Angenommen, wir haben beide void M(string x){}und void M(params string[] x){}. Was macht M(null)und warum? Wie unterscheidet sich das vom vorherigen Fall?

Eric Lippert
quelle
Ch2: P(null)vs. P((object)null)vs. P((object[])null)- wo finde ich eine Erklärung für diesen Unterschied? Es fühlt sich an, als nullhätte es einen speziellen Typ , der eher in Array als in object ( P(null)) konvertiert , aber die Konvertierung in einen String oder ein Array von Strings mehrdeutig findet ( M(null)) ... was sich sehr seltsam anfühlt, würde erwarten, dass er entweder in beiden Fällen mehrdeutig ist oder auswählt die Single-Arg-Version (was es nicht tut). Aber ich denke, es geht mehr darum params, irgendwie generisch zu sein , wie Universal Reference ( &&) in C ++ - Vorlagen, und daher besser übereinzustimmen (in Ch2, nicht in Ch3).
Firda
@firda: Die Erklärung finden Sie in der C # -Spezifikation. Der Grund für die Fremdheit ist: null kann in Objekt, Zeichenfolge, Objekt [] und Zeichenfolge [] konvertiert werden. Die Frage zur Überlastungsauflösung lautet also: Welche Konvertierung ist am besten ? Die Kontrollregel in diesem Fall ist spezifisch ist besser als allgemein . Wie erkennen wir, welcher Typ spezifischer ist? Die Regel lautet: Alle Giraffen sind Tiere, aber nicht alle Tiere sind Giraffen. Daher ist Giraffe spezifischer als Tier. Alle object[]sind object, aber nicht alle objectsind object[], ist daher object[]spezifischer.
Eric Lippert
@firda: Jetzt weißt du, warum Strings mehrdeutig sind. Es ist NICHT wahr, dass "alle string[]sind string". In der Tat NO string[]sind stringund NO stringsind string[], so stringist nicht spezifischere oder allgemeiner als string[], und wir bekommen eine Fehler Mehrdeutigkeit , wenn wählen gefragt.
Eric Lippert
Alle object[]sind object... object[]ist spezifischer, also P(null)gilt das spezifischere Array, danke, das hat mir gefehlt. Hier finden Sie einige Regeln: docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
firda
5

Habe gerade einen kleinen Prototyp gemacht. Die Antwort scheint zu sein, dass paramses sich einfach um syntaktischen Zucker zum Übergeben eines Arrays handelt. Das ist keine wirkliche Überraschung. Ich habe zwei Versionen derselben Methode erstellt, wobei der einzige Unterschied das Schlüsselwort "params" ist. Die für beide generierte IL war identisch, außer dass a System.ParamArrayAttributeauf die paramsVersion angewendet wurde .

Außerdem war die an der Aufrufstelle generierte IL zwischen dem Aufrufen der Methode mit einer manuell deklarierten new int[]Methode und dem Aufrufen der Methode nur unter Verwendung der paramsArgumente dieselbe .

Die Antwort scheint also "Bequemlichkeit" zu sein. Es scheint keinen Leistungsunterschied zu geben. Sie können paramsstattdessen auch eine Funktion mit einem Array aufrufen , was auch nicht sonderlich überraschend ist. Es kommt darauf an, ob es für den Verbraucher Ihrer Methode einfacher ist, sie mit einer beliebigen Anzahl von Parametern aufzurufen (z. B. someMethod(1, 2, 3)), als immer zuerst eine Sammlung erstellen zu müssen (z someMethod(new List<int>() { 1, 2, 3 } ). B. ).

digitlworld
quelle
4

Die Funktion unbegrenzter Parameter bietet in vielen Szenarien die folgenden Vorteile:

  1. Lose Kopplung
  2. Verbesserte Wiederverwendbarkeit
  3. Bessere Gesamtleistung der Anwendung

Hier ist ein Beispiel, bei dem die Option für unbegrenzte Parameter eine gute Wahl ist

Beachten Sie, dass eine Anwendung zum Senden von E-Mails erstellt werden muss.

Die Funktion, die die E-Mail sendet, muss entweder einzelne oder mehrere Werte für die Felder "An", "CC" und "BCC" verarbeiten können.

Wenn die Parametertypen als Arrays oder Listen für alle Felder (To, CC, BCC) festgelegt sind, muss sich die aufrufende Funktion mit der Komplexität der Definition von 3 Arrays oder Listen befassen, um die E-Mail-Absenderfunktion aufzurufen .

Selbst wenn der Anrufer eine E-Mail an nur eine Adresse senden möchte, zwingt die E-Mail-Absenderfunktion den Anrufer, 3 verschiedene Arrays als Parameter zu definieren und zu senden.

Wenn die E-Mail-Absenderfunktion den unbegrenzten Parameteransatz verwendet, muss die Anruferfunktion nicht die gesamte Komplexität bewältigen.

Der Ansatz mit unbegrenzten Parametern trägt zu einer besseren Laufzeitleistung der Anwendung bei, indem die Erstellung von Arrays oder Listen vermieden wird, wo immer dies nicht erforderlich ist.

Gopinath
quelle
2

Aus einer nicht leistungsfähigen Stilperspektive ist das paramsSchlüsselwort sehr hilfreich, wenn Sie eine optionale Liste von Parametern senden möchten.

Persönlich würde ich verwenden, paramswenn mein Code so etwas wie war

SomeMethod('Option1', 'Option17');

void SomeMethod(params string[] options)
{
    foreach(var option in options)
    {
        switch(option): ...
    }
}

Das Schöne daran ist, dass ich diese Methode überall anwenden kann, ohne jedes Mal ein Array oder eine Liste erstellen zu müssen.

Ich würde verwenden arrayoder listwenn ich weiß, werde ich dieser Funktion immer einen Datensatz übergeben, der bereits wie zusammengestellt ist

List<User> users = GetUsersFromDB();
SomeMethod(users);

Ich sehe den Vorteil paramsin der Flexibilität, die es hinzufügt. Es mag eine relativ geringe Auswirkung auf Ihren Code haben, aber es ist immer noch ein gutes Werkzeug.

Olivensaft
quelle
1

Die Aufrufkonvention ist anders. Beispielsweise ...

public class Test
{
    public void Method1( params int[] nums )
    {
        nums.ToList().ForEach( n => Console.WriteLine(n) );
    }

    public void Method2( List<int> nums )
    {
        nums.ForEach( n  => Console.WriteLine(n) );
    }   
}

void Main()
{   
    var t = new Test();
    t.Method1( 1, 2, 3, 4 );
    t.Method2( new List<int>() { 1, 2, 3, 4 } );
}

Im ersten Fall können Sie so viele Ints wie separate Parameter an die Methode übergeben. Im zweiten Fall müssten Sie eine Liste instanziieren und übergeben.

JP Alioto
quelle