2017-05-11 28 views
8

Fiddle here. bir işlev (string a, string b) F() Verilen C# 7 değeri tuple/yapışma asimetrisi

, bunu döndüren tuple deconstruct:

var (a, b) = F(); 

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

Ya da sadece atayabilirsiniz:

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

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

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

Sınıf deconstructors ilk vaka gibi davranırlar. Bir sınıf CDeconstructor(out string a, out string b) ile Verilen:

Ama derleyici örtülü bir tuplea dönüştürmek için Deconstructor kullanmaz:

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

Açıkçası mekanik Deconstructor dayalı bir örtük dönüştürme yazabilirsiniz : yapısöküm ve atama durumları arasında sözdiziminde görsel benzerlik dikkate alınmaksızın

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

olarak Bir tuple bir referansın imzalanması, bir sınıfa değişkenlerin deşifre edilmesi ve sonra da yeni bir tuple yerleştirilmesi ile aynı değildir. Ancak, dolaylı olarak (int x, int y)'u (double x, double y)'a dönüştürebilirsiniz. Değer tupl'leri, göründüğü gibi yaptıklarını söyleyen sözdizimsi şekerleme özelliğidir ve uygulama ayrıntılarını boşver.

Bunu düşünürsem, C# takımı bunu düşündü ve örtük dönüştürme için "büyü" desteği eklememeyi seçtiyse, iyi bir nedenleri vardı.

Gizli dönüşümün otomatik olarak yapılmasının neden hatalı bir fikir olabileceğinin pozitif bir nedeni var mı?

Ya da maliyeti haklı çıkaracak kadar değerli sayılmayan özelliklerden biri mi?

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# ekibi herkes daha akıllı olmayabilir, ama onlar en azından benim kadar akıllı olduğunu bahis para kaybetti asla:


İşte that fiddle gelen kod.

+0

Açıkçası, örtülü Yapıçözüm genellikle başka birine bir sınıftan örtük dönüştürme istemiyoruz aynı şekilde istemiyoruz. Ayrıca, aynı kaynaktan gelen hem tuple hem de deconstructed değişkenleri kullanmak çok mantıklı değildir. Bu sadece kodu anlamak zorlaştıracaktı. Ve bir dil tasarımcısı olarak, yine de daha sıkı çalışmaya başlamak ve sonradan aksine tersine genelleştirmek mantıklı. C# şimdi en büyük tasarım yanlışlıkla biri olarak kabul edilir Örneğin, referans tipleri varsayılan olarak null olması edilir ... – Phil1970

cevap

5

dekonstürüksiyon örtülü dönüştürücüler gibi hareket sahip olma yeteneği istedi şeydi (bana göre, bu yüzden burada önyargılı değilim). (Ben yine de okumak gibi) ekibinden yanıt C# 7 sürümüne çok yakın istedi ve uygulamak için çok uzun sürerdi, bu yüzden yukarı değerlendirilmek üzere olduğuydu. Şimdi bir kırılma değişikliği olduğu için, bu gerçekleşecek bir şey değil.

konuda fiili tartışma için "Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types" roslyn repo sorunu bakınız.

5

(string a, string b) abab adlı tanımlama grubu tipi (string a, string b) bir tek değişkeni bildirir. Bu ab.a veya ab.b yazmanıza izin verir, ancak a veya b.

(string a, string b) f = c;, bu tuple türüne ilişkisiz bir C türünü dönüştürmeyi dener. Bir oyuncu sen yazmazsan, bunun gerçekleşmesinin bir yolu yoktur.

Özellikle, adından da anlaşıldığı üzere, yıkım yalnızca değişkenlere atamanızı sağlar; ilişkisiz bir türe dönüştürmenize izin vermez.C# 7 yayınlanmadan önce

3

Yapmaya çalıştığınız şeyi elde etmenin bir yolu: Kod örneğinizde, (string a, string b) f = c; yerine, (string a, string b) f = (_, _) = c; kullanın.

Ayrıca ihtiyaç tanımlama grubu türüyle türünden bir kullanıcı tanımlı dönüşüm yazabiliriz.

+0

Gerçekten burada hile hayran! Bunu üretim kodunda görmek istemiyorum, ama düzgün :) –