2017-05-11 35 views
8

Fiddle here.C# 7 wartość krotki/asymetria dekonstrukcji

Biorąc funkcją (string a, string b) F() można dekonstrukcji krotki powraca:

var (a, b) = F(); 

(string c, string d) = F(); 

Albo można po prostu przypisać go:

var (a, b) e = F(); 

(string a, string b) f = F(); 

var g = F(); // One of these things is not like the others. 

deconstructors klasy zachowują się jak pierwszym przypadku. Biorąc pod uwagę klasę C z Deconstructor(out string a, out string b):

Ale kompilator nie użyje Deconstructor niejawnie przekonwertować go na krotki:

// Cannot implicitly convert type 'C' to '(string a, string b)' 
var (a, b) l = c; 

Oczywiście można mechanicznie napisać niejawna konwersja na podstawie Deconstructor :

public static implicit operator (string a, string b) (C c) 
{ 
    c.Deconstruct(out string a, out string b); 
    return (a, b); 
} 

Bez względu na podobieństwa wizualnego w składni między dekonstrukcji i przypisania przypadkach, podpisanie odniesienia do krotki to nie to samo, co dekonstruowanie klasy na zmienne, a następnie umieszczanie ich w nowej krotce. Można jednak niejawnie przekonwertować (int x, int y) na (double x, double y). Krotki wartości to rodzaj funkcji syntaktycznego cukru, w której robi się to, na co wygląda, i nie ma nic przeciwko szczegółom implementacji.

Jeśli pomyślałem o tym, zespół C# pomyślał o tym i jeśli nie zdecydowali się dodać "magicznego" wsparcia dla niejawnej konwersji, mieli dobry powód .

Czy istnieje pozytywny powód, dla którego automatyczne wykonanie niejawnej konwersji byłoby złym pomysłem?

Czy jest to jedna z tych cech, które po prostu nie zostały uznane za wystarczająco wartościowe, aby uzasadnić koszty?


Oto kod z that fiddle: # zespół

public class Program 
{ 
    public static void Main() 
    { 
     (string a, string b) = F(); 

     (string a, string b) ab = F(); 

     Console.WriteLine($"a: {a} b: {b} ab: {ab}"); 


     var c = new C(); 

     (string d, string e) = c; 

     // Cannot implicitly convert type 'C' to '(string a, string b)' 
     (string a, string b) f = c; 

     Console.WriteLine($"d: {d} e: {e} f: {f}"); 

     // Covariance 
     (object c, object d) g = F(); 
     // Implicit conversion 
     (double x, double y) t = G(); 
    } 

    public static (string a, string b) F() 
     => ("A", "B"); 

    public static (int x, int y) G() 
     => (0, 1); 
} 

public class C 
{ 
    public String A = "A"; 
    public String B = "B"; 

    public void Deconstruct(out String a, out String b) 
    { 
     a = A; 
     b = B; 
    } 
} 

C nie może być mądrzejszy niż wszyscy, ale nigdy nie stracił pieniądze zakłady były co najmniej tak samo mądry jak ja.

+0

Oczywiście, nie chcesz niejawnej dekonstrukcji w taki sam sposób, w jaki zwykle nie chcesz niejawnej konwersji z klasy na inną. Nie ma też sensu używanie zarówno krotek, jak i zdekonstruowanych zmiennych z tego samego źródła. Uczyniłoby to kod trudniejszym do zrozumienia. I jako projektant języka, sensowne jest, aby zacząć bardziej rygorystyczne, a następnie ostatecznie uogólniać, niż przeciwnie. Na przykład fakt, że typy referencyjne domyślnie są zerowane, C# jest teraz uważany za jeden z największych błędów projektowych ... – Phil1970

Odpowiedz

5

Możliwość dekonstrukcji zachowuje się jak niejawne konwertery było czymś, o co prosiła (przeze mnie, więc jestem stronniczy tutaj) przed wydaniem C# 7. Odpowiedź zespołu brzmiała (tak jak i ja to czytałem), że został poproszony o zbyt bliskie zwolnienie C# 7 i zająłby zbyt długo, aby go wdrożyć, więc nie był do rozważenia. Ponieważ teraz będzie to przełomowa zmiana, nie będzie to miało nigdy większego sensu.

Przeczytaj "Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types" numer Roslyn w sprawie repo, aby porozmawiać na ten temat.

5

(string a, string b) ab deklaruje pojedynczy zmienną typu krotki (string a, string b) nazwie ab. To pozwala pisać ab.a lub ab.b, ale nie a ani b.

(string a, string b) f = c; próbuje przekonwertować niepowiązany typ C na ten typ krotki. Dopóki nie napiszesz obsady, nie ma takiej możliwości.

W szczególności, jak sama nazwa wskazuje, destrukturyzacja pozwala tylko przypisać do zmiennych; nie pozwala na konwersję do niepowiązanych typów.

3

Oto jeden ze sposobów osiągnięcia tego, co próbujesz zrobić: w kodzie przykładowym zamiast (string a, string b) f = c; użyj (string a, string b) f = (_, _) = c;.

Można również napisać konwersję zdefiniowaną przez użytkownika z typu do potrzebnego typu krotki.

+0

Naprawdę podziwiam tutaj tę sztuczkę! Nigdy nie chciałbym tego zobaczyć w kodzie produkcyjnym, ale jest fajnie :) –