26 Stimmen

Zuweisung von Werten eines Arrays an separate Variablen in einer Zeile

Kann ich jeden Wert in einem Array zu separaten Variablen in einer Zeile in C# zuweisen? Hier ist ein Beispiel in Ruby-Code von dem, was ich will:

irb(main):001:0> str1, str2 = ["hey", "now"]
=> ["hey", "now"]
irb(main):002:0> str1
=> "hey"
irb(main):003:0> str2
=> "now"

Ich bin nicht sicher, ob das, was ich will, in C# möglich ist.

Edit : Für diejenigen, die vorschlagen, dass ich die Zeichenketten "hey" und "now" einfach Variablen zuweise, ist das nicht das, was ich will. Stellen Sie sich das Folgende vor:

irb(main):004:0> val1, val2 = get_two_values()
=> ["hey", "now"]
irb(main):005:0> val1
=> "hey"
irb(main):006:0> val2
=> "now"

Nun ist die Tatsache, dass die Methode get_two_values zurückgegebenen Zeichenketten "hey" und "now" ist willkürlich. Es können zwei beliebige Werte zurückgegeben werden, die nicht einmal Zeichenketten sein müssen.

4 Stimmen

Wow, hässlich und verwirrend. Erinnert mich an mein letztes Date.

3 Stimmen

@Will: Really? Ich denke, es ist schön und prägnant, aber trotzdem klar und lesbar. Ich mag die Funktion in Python sehr und verwende sie häufig.

1 Stimmen

Aus Sicht von C# auf jeden Fall. Es sieht so aus, als würden Sie einen Verweis auf ein einzelnes Array zwei verschiedenen Variablen zuweisen... wie str1 = new string[] {"one", "two"}; str2 = str1; Also ist es für C#-Entwickler sofort verwirrend. Der hässliche Teil war nur, damit ich den Witz unterbringen konnte.

18voto

JaredPar Punkte 699699

Dies ist in C# nicht möglich.

Das Naheliegendste, was mir einfällt, ist die Verwendung der Initialisierung in derselben Zeile mit Indizes

strArr = new string[]{"foo","bar"};
string str1 = strArr[0], str2 = strArr[1];

1 Stimmen

Das ist im Wesentlichen das, was Ruby im Verborgenen tut; das, was @Sarah tun will, ist im Grunde syntaktischer Zucker.

0 Stimmen

Ich würde es als syntaktisches Irgendwas bezeichnen. Versteckt Ruby die Unterschiede zwischen der Speicherzuweisung von Primitiven und Referenztypen?

1 Stimmen

Ruby ist eine Skriptsprache. Es gibt keine primitiven Typen; sie befinden sich alle auf dem Heap - Referenztypen.

15voto

user1414213562 Punkte 4133

Aktualisierung: In C#7 können Sie problemlos mehrere Variablen auf einmal zuweisen, indem Sie Tupel verwenden. Um Array-Elemente an Variablen zuzuweisen, müssen Sie eine entsprechende Deconstruct() Erweiterungsmethoden:

Eine andere Möglichkeit, Tupel zu verbrauchen, besteht darin, sie zu dekonstruieren. Eine dekonstruierende Deklaration ist eine Syntax zur Aufteilung eines Tupels (oder eines anderen Wertes) in seine Teile zu zerlegen und diese Teile einzeln neuen Variablen zuzuweisen:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");

In einer dekonstruierenden Erklärung können Sie var für die einzelnen Variablen deklarieren:

(var first, var middle, var last) = LookupName(id1); // var inside

Oder Sie können auch eine einzelne var außerhalb der Klammern als Abkürzung:

var (first, middle, last) = LookupName(id1); // var outside

Sie können auch in bestehende Variablen dekonstruieren mit einem dekonstruierenden Zuweisung dekonstruieren:

(first, middle, last) = LookupName(id2); // deconstructing assignment

Dekonstruktion ist nicht nur für Tupel geeignet. Jeder Typ kann dekonstruiert werden, solange er eine Dekonstruktionsmethode (Instanz oder Erweiterung) der der Form hat:

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }

Die Ausgangsparameter sind die Werte, die sich aus den Dekonstruktion ergeben.

(Warum verwendet es out-Parameter, anstatt ein Tupel zurückzugeben? Das ist damit Sie mehrere Überladungen für eine unterschiedliche Anzahl von Werten haben können. Werte haben kann).

class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}

(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

Es wird ein gängiges Muster sein, dass Konstruktoren und Dekonstrukteure auf diese Weise "symmetrisch" sind. https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/


Alte Antwort:

In der Tat können Sie eine ähnliche Funktionalität in C# erreichen, indem Sie Erweiterungsmethoden wie die folgende verwenden (Hinweis: Ich habe die Überprüfung, ob die Argumente gültig sind, nicht einbezogen):

public static void Match<T>(this IList<T> collection, Action<T,T> block)
{
    block(collection[0], collection[1]);
}
public static void Match<T>(this IList<T> collection, Action<T,T,T> block)
{
    block(collection[0], collection[1], collection[2]);
}
//...

Und Sie können sie so verwenden:

new[] { "hey", "now" }.Match((str1, str2) =>
{
    Console.WriteLine(str1);
    Console.WriteLine(str2);
});

Falls ein Rückgabewert von einer Funktion benötigt wird, würde die folgende Überladung funktionieren:

public static R Match<T,R>(this IList<T> collection, Func<T, T, R> block)
{
    return block(collection[0], collection[1]);
}

private string NewMethod1()
{   
    return new[] { "hey", "now" }.Match((str1, str2) =>
    {
        return str1 + str2;
    });
}

Auf diese Weise:

  • Sie vermeiden die Wiederholung von Array-Namen wie in der von JaredPar und anderen vorgeschlagenen Lösung; die Liste der "Variablen" ist einfach zu lesen.

  • Sie vermeiden die explizite Deklaration von Variablentypen wie bei der Lösung von Daniel Earwicker.

Der Nachteil ist, dass man am Ende einen zusätzlichen Codeblock hat, aber ich denke, das ist es wert. Sie können Code-Snippets verwenden, um die manuelle Eingabe von geschweiften Klammern usw. zu vermeiden.

Ich weiß, es ist eine 7 Jahre alte Frage, aber nicht so lange Zeit vor ich brauchte eine solche Lösung - einfach geben Namen zu Array-Elemente in die Methode übergeben (nein, mit Klassen/Strukturen anstelle von Arrays war nicht praktisch, weil für gleiche Arrays ich unterschiedliche Elementnamen in verschiedenen Methoden benötigen könnte) und leider landete ich mit Code wie diese:

var A = points[0];
var A2 = points[1];
var B = points[2];
var C2 = points[3];
var C = points[4];

Jetzt könnte ich schreiben (in der Tat habe ich eine dieser Methoden gerade überarbeitet!):

points.Match((A, A2, B, C2, C) => {...});

Meine Lösung ähnelt dem Musterabgleich in F#, und ich wurde von dieser Antwort inspiriert: https://stackoverflow.com/a/2321922/6659843

4voto

Daniel Earwicker Punkte 111630

Der reale Anwendungsfall hierfür ist die Bereitstellung einer bequemen Möglichkeit, mehrere Werte aus einer Funktion zurückzugeben. Es handelt sich also um eine Ruby-Funktion, die eine feste Anzahl von Werten in einem Array zurückgibt, und der Aufrufer möchte sie in zwei separaten Variablen haben. In diesem Fall ist die Funktion am sinnvollsten:

first_name, last_name = get_info() // always returns an array of length 2

Um dies in C# auszudrücken, würden Sie die beiden Parameter mit out in der Methodendefinition, und geben Sie void :

public static void GetInfo(out string firstName, out string lastName)
{
    // assign to firstName and lastName, instead of trying to return them.
}

Und so zu nennen:

string firstName, lastName;
SomeClass.GetInfo(out firstName, out lastName);

Das ist nicht so schön. Hoffentlich wird eine zukünftige Version von C# dies ermöglichen:

var firstName, lastName = SomeClass.GetInfo();

Um dies zu ermöglichen, muss die GetInfo Methode würde eine Tuple<string, string> . Dies wäre eine nicht bahnbrechende Änderung der Sprache, da die derzeitigen rechtlichen Verwendungen von var sind sehr restriktiv, so dass die obige Syntax der "Mehrfachdeklaration" noch nicht sinnvoll eingesetzt werden kann.

2voto

Randolpho Punkte 54011

Sie können dies in einer Zeile tun, aber nicht als eine Anweisung.

Zum Beispiel:

int str1 = "hey"; int str2 = "now";

Python und Ruby unterstützen die Zuweisung, die Sie versuchen, zu tun; C # nicht.

2voto

John Alexiou Punkte 25680

Sie können dies in C# tun

string str1 = "hey", str2 = "now";

oder Sie können sich so etwas ausdenken

        int x, y;
        int[] arr = new int[] { x = 1, y = 2 };

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X