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.
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