Frage

Ich habe solche Methoden gesehen:

public void Foo(List<string> list)
{
    list.Add("Bar");
}

Ist diese gute Praxis, Parameter in einer Methode zu ändern?

Wäre das nicht besser?

public List<string> Foo(List<string> list)
{
    // Edit
    List<string> newlist = new List<string>(list);
    newlist.Add("Bar");
    return newlist;
}

Es fühlt sich einfach so an, als hätte das erste Beispiel unerwartete Nebenwirkungen.

War es hilfreich?

Lösung

In dem Beispiel, das Sie gegeben haben, scheint mir das erste viel schöner zu sein als der zweite. Wenn ich eine Methode sah, die eine Liste akzeptierte und auch eine Liste zurückgab, wäre meine erste Annahme, dass sie eine neue Liste zurückgab und nicht die, die sie erhielten. Die zweite Methode ist daher die mit unerwarteten Nebenwirkungen.

Solange Ihre Methoden angemessen genannt werden, besteht bei der Änderung des Parameters wenig Gefahr. Bedenken Sie:

public void Fill<T>(IList<T> list)
{
    // add a bunch of items to list
}

Mit einem Namen wie "FILL" können Sie ziemlich sicher sein, dass die Methode die Liste ändert.

Andere Tipps

Ehrlich gesagt, in diesem Fall tun beide Methoden mehr oder weniger dasselbe. Beide ändern die List das wurde eingegangen.

Wenn das Ziel nach einer solchen Methode unababstimmung werden soll, sollte das zweite Beispiel eine Kopie des List das wurde eingesandt und dann die durchführen Add Betrieb auf dem neuen List und dann zurück.

Ich bin weder mit C# noch .NET vertraut, also wäre ich etwas in der Reihe von:

public List<string> Foo(List<string> list)
{
    List<string> newList = (List<string>)list.Clone();
    newList.Add("Bar");
    return newList;
}

Auf diese Weise die Methode, die das aufruft Foo Methode wird das neu erstellt List kehrte zurück und das Original List Das wurde nicht berührt.

Dies liegt wirklich dem "Vertrag" Ihrer Spezifikationen oder API ListS kann einfach geändert werden, ich sehe kein Problem mit dem ersten Ansatz.

Sie tun genau das Gleiche in beiden Methoden, nur einer von ihnen gibt dieselbe Liste zurück.

Es hängt meiner Meinung nach wirklich davon ab, was Sie tun. Stellen Sie einfach sicher, dass Ihre Dokumentation klar ist, was los ist. Schreiben Sie Vorkonditionen und Post-Konditionen, wenn Sie sich mit so etwas befassen.

Es ist eigentlich nicht so unerwartet, dass eine Methode, die eine Liste als Parameter einnimmt, die Liste ändert. Wenn Sie eine Methode wünschen, die nur aus der Liste liest, verwenden Sie eine Schnittstelle, die nur das Lesen ermöglicht:

public int GetLongest(IEnumerable<string> list) {
    int len = 0;
    foreach (string s in list) {
        len = Math.Max(len, s.Length);
    }
    return len;
}

Durch die Verwendung einer Schnittstelle wie diese verbieten Sie die Methode nicht nur, die Liste zu ändern, sondern auch flexibler, da sie beispielsweise jede Sammlung verwenden kann, die die Schnittstelle implementiert, wie beispielsweise ein String -Array.

Einige andere Sprachen haben eine const Schlüsselwort, das auf Parameter angewendet werden kann, um eine Methode zu verbieten, sie zu ändern. Da .NET Schnittstellen hat, die Sie dafür verwenden können, und Strings, die unveränderlich sind, gibt es nicht wirklich einen Bedarf an const Parameter.

Das Aufkommen von Erweiterungsmethoden hat es etwas einfacher gemacht, mit Methoden umzugehen, die Nebenwirkungen einführen. Zum Beispiel wird es in Ihrem Beispiel viel intuitiver zu sagen

public static class Extensions
{
  public static void AddBar(this List<string> list)
  {
     list.Add("Bar");
  }
}

und ruf es mit

mylist.AddBar();

Das macht es klarer, dass mit der Liste etwas passiert.

Wie in den Kommentaren erwähnt, ist dies in Listen am nützlichsten, da Änderungen an einer Liste tendenziell verwirrender sein können. Bei einem einfachen Objekt würde ich dazu neigen, das an Ort und Stelle zu änderne Objekt nur zu ändern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top