2009-09-14 16 views
14

Czy mogę przypisać każdą wartość w tablicy do oddzielenia zmiennych w jednym wierszu w C#? Oto przykład kodu Ruby tego, czego chcę:C# przypisać wartości tablicy do oddzielenia zmiennych w jednym wierszu

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

Nie jestem pewien, czy to, czego chcę, jest możliwe w języku C#.

Edytuj: dla tych, którzy sugerują, że po prostu przypisuję ciągi "hej" i "teraz" do zmiennych, to nie jest to, czego chcę. Wyobraźmy sobie, co następuje:

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

Teraz fakt, że metoda get_two_values powrócił ciągi „hej” i „teraz” jest arbitralne. W rzeczywistości może zwrócić dowolne dwie wartości, nawet nie muszą to być łańcuchy.

+3

Wow, brzydki i zagmatwany. Przypomina mi o mojej ostatniej randce. – Will

+1

@Will: Naprawdę? Uważam, że jest ładny i zwięzły, a jednocześnie czytelny i czytelny. Raczej podoba mi się funkcja w Pythonie i często go używam. – Randolpho

+1

Z perspektywy C#, zdecydowanie. Wygląda na to, że przypisujesz odwołanie do pojedynczej tablicy do dwóch różnych zmiennych ... jak str1 = nowy ciąg [] {"jeden", "dwa"}; str2 = str1; Jest to natychmiast mylące dla programistów C#. Ten brzydki kawałek był taki, że mogłem zmieścić się w żartach. – Will

Odpowiedz

12

Nie jest to możliwe w języku C#.

Najbliższy rzeczą mogę myśleć jest użycie inicjalizacji w tej samej linii z Indexs

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

To właśnie to, co rubin robi pod kołdrą; rzecz, której @Sarah chce zrobić, to w zasadzie cukier syntaktyczny. – Randolpho

+0

Nazwałbym to słowem syntaktycznym. Czy Ruby ukrywa różnice między alokacją pamięci prymitywów a typami referencyjnymi? – Will

+1

Ruby jest językiem skryptowym. Nie ma żadnych typów pierwotnych; wszyscy są na kupie - typy referencyjne. – Randolpho

1

Można to zrobić w jednej linii, ale nie jako jedna instrukcja.

Na przykład:

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

Python i Ruby wspierać przypisanie próbujesz zrobić; C# nie.

2

Nie jestem pewien, czy to, czego chcę, to możliwe w języku C#.

To nie jest.

0

Nie, ale można zainicjować tablicę ciągów:

string[] strings = new string[] {"hey", "now"}; 

Mimo że prawdopodobnie nie jest zbyt przydatna dla Ciebie. Szczerze jej nie trudno umieścić je na dwóch liniach:

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

rzeczywistym świecie przypadek użycia tego zapewnia wygodny sposób zwracać wiele wartości z funkcji. Tak więc jest to funkcja Ruby, która zwraca stałą liczbę wartości w tablicy, a wywołujący chce ich w dwóch oddzielnych zmiennych. To właśnie cecha sprawia, że ​​największy sens:

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

wyrazić to w C# byś zaznaczyć dwa parametry z out w definicji metody i powrót void:

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

I tak to nazwać :

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

To nie jest takie miłe. Mam nadzieję, że niektóre przyszła wersja C# pozwala na to:

var firstName, lastName = SomeClass.GetInfo(); 

Aby to umożliwić, metoda GetInfo zwróci Tuple<string, string>.Byłaby to niezłamująca zmiana w stosunku do języka, ponieważ obecne zastosowania prawne var są bardzo restrykcyjne, więc nie ma jeszcze ważnego zastosowania dla powyższej składni "wielokrotnej deklaracji".

2

Można to zrobić w C#

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

czy można być fantazyjny jak ten

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

Aktualizacja: W języku C# 7 można łatwo przypisać wiele zmiennych na raz za pomocą krotki. Aby przypisać elementy tablicy do zmiennych, należy napisać odpowiednią metodę rozszerzenia Deconstruct():

Innym sposobem na wykorzystanie krotek jest ich dekonstrukcja. Dekonstrukcji deklaracja jest składnia do dzielenia krotki (lub inną wartość) do jego części i przypisanie tych części indywidualnie do świeżych zmiennych:

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

W deklaracji dekonstrukcji można użyć var ​​dla poszczególnych zmiennych zadeklarowanych :

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

Albo nawet umieścić pojedynczy var poza nawias jako skrót:

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

Można także dekonstrukcji w istniejących zmiennych z dekonstrukcji przypisania:

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

Dekonstrukcja nie jest tylko dla krotki. Każdy typ może zostać rozebrany, ile ma rozszerzenie (wystąpienie lub) metoda Deconstructora z postać:

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

Out parametry stanowią wartości, które wynikają z rozbiórki.

(Dlaczego używa parametrów zamiast zwracania krotki? To jest , dzięki czemu można mieć wiele przeciążeń dla różnych liczb wartości ).

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); 

To będzie wspólny wzorzec mieć konstruktorzy i deconstructors być „symetryczny” w ten sposób. https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/


Old odpowiedź:

W rzeczywistości, można uzyskać podobną funkcjonalność w C# za pomocą metody rozszerzenie tak (uwaga: nie obejmować sprawdzenie, czy argumenty są ważne) :

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]); 
} 
//... 

I można ich używać tak:

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

W przypadku potrzebna jest wartość zwracana z funkcji, co następuje przeciążenie będzie działać:

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; 
    }); 
} 

w następujący sposób:

  • uniknąć konieczności powtarzania nazwę tablicy jak w roztworze zaproponowany przez JaredPar i innych; lista "zmiennych" jest łatwa do odczytania.

  • Unikasz konieczności jawnego zadeklarowania typów zmiennych, jak w rozwiązaniu Daniela Earwickera.

Wadą jest to, że kończy się dodatkowy blok kodu, ale myślę, że warto. Możesz użyć fragmentów kodu, aby uniknąć ręcznego wpisywania nawiasów klamrowych itp.

Wiem, że jest to 7-letnie pytanie, ale nie tak dawno temu potrzebowałem takiego rozwiązania - łatwe nadawanie nazw elementom tablicy przekazanym do metody (nie, używanie klas/struktur zamiast tablic było niepraktyczne, bo dla samych tablic mogę potrzebować różne nazwy elementu w różnych metod) i niestety skończyło się z kodem tak:

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

teraz mogę napisać (w rzeczywistości, mam refactored jedną z tych metod już teraz!):

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

Moje rozwiązanie jest podobne do dopasowywania wzorców w F # i I był inspirowany tej odpowiedzi: https://stackoverflow.com/a/2321922/6659843

0

można użyć nazwana krotki z C# 7 teraz.

{ 
    (string part1, string part2) = Deconstruct(new string[]{"hey","now"}); 
} 

public (string, string) Deconstruct(string[] parts) 
{ 
    return (parts[0], parts[1]); 
}