Apa gunanya downcasting?

68

Downcasting berarti casting dari kelas dasar (atau antarmuka) ke kelas subclass atau daun.

Contoh downcast mungkin jika Anda beralih dari System.Objectke jenis lainnya.

Downcasting tidak populer, mungkin bau kode: Doktrin Berorientasi Objek adalah lebih suka, misalnya, mendefinisikan dan memanggil metode virtual atau abstrak daripada downcasting.

  • Apa, jika ada, kasus penggunaan yang baik dan tepat untuk downcasting? Artinya, dalam keadaan apa sajakah yang tepat untuk menulis kode yang mengecewakan?
  • Jika jawaban Anda adalah "tidak ada", lalu mengapa downcasting didukung oleh bahasa?
ChrisW
sumber
5
Apa yang Anda gambarkan biasanya disebut "downcasting". Berbekal pengetahuan itu, bisakah Anda melakukan riset sendiri terlebih dahulu, dan menjelaskan mengapa alasan yang Anda temukan tidak mencukupi? TL; DR: downcasting merusak pengetikan statis, tetapi kadang-kadang sistem tipe terlalu membatasi. Jadi masuk akal jika bahasa menawarkan downcasting yang aman.
amon
Maksud Anda downcasting? Mendatang akan naik melalui hierarki kelas, yaitu dari subclass ke superclass, berlawanan dengan downcasting, dari superclass ke subclass ...
Andrei Socaciu
Permintaan maaf saya: Anda benar. Saya mengedit pertanyaan untuk mengubah nama "upcast" menjadi "downcast".
ChrisW
@amon en.wikipedia.org/wiki/Downcasting memberikan "convert to string" sebagai contoh (yang didukung oleh .Net menggunakan virtual ToString); contoh lainnya adalah "wadah Java" karena Java tidak mendukung obat generik (yang C # tidak). stackoverflow.com/questions/1524197/downcast-and-upcast mengatakan apa downcasting adalah , tetapi tanpa contoh ketika itu tepat .
ChrisW
4
@ ChrisW Itu before Java had support for generics, tidak because Java doesn't support generics. Dan Amon cukup banyak memberi Anda jawaban - ketika sistem tipe yang Anda gunakan terlalu membatasi dan Anda tidak dalam posisi untuk mengubahnya.
Ordous

Jawaban:

12

Berikut adalah beberapa penggunaan downcasting yang tepat.

Dan saya dengan penuh hormat sangat tidak setuju dengan orang lain di sini yang mengatakan penggunaan downcast jelas merupakan bau kode, karena saya percaya tidak ada cara lain yang masuk akal untuk menyelesaikan masalah yang terkait.

Equals:

class A
{
    // Nothing here, but if you're a C++ programmer who dislikes object.Equals(object),
    // pretend it's not there and we have abstract bool A.Equals(A) instead.
}
class B : A
{
    private int x;
    public override bool Equals(object other)
    {
        var casted = other as B;  // cautious downcast (dynamic_cast in C++)
        return casted != null && this.x == casted.x;
    }
}

Clone:

class A : ICloneable
{
    // Again, if you dislike ICloneable, that's not the point.
    // Just ignore that and pretend this method returns type A instead of object.
    public virtual object Clone()
    {
        return this.MemberwiseClone();  // some sane default behavior, whatever
    }
}
class B : A
{
    private int[] x;
    public override object Clone()
    {
        var copy = (B)base.Clone();  // known downcast (static_cast in C++)
        copy.x = (int[])this.x.Clone();  // oh hey, another downcast!!
        return copy;
    }
}

Stream.EndRead/Write:

class MyStream : Stream
{
    private class AsyncResult : IAsyncResult
    {
        // ...
    }
    public override int EndRead(IAsyncResult other)
    {
        return Blah((AsyncResult)other);  // another downcast (likely ~static_cast)
    }
}

Jika Anda akan mengatakan ini bau kode, Anda perlu memberikan solusi yang lebih baik untuk mereka (bahkan jika mereka dihindari karena ketidaknyamanan). Saya tidak percaya ada solusi yang lebih baik.

Mehrdad
sumber
9
"Code bau" tidak berarti "desain ini pasti buruk " itu berarti "desain ini mencurigakan ". Bahwa ada fitur bahasa yang secara inheren mencurigakan adalah masalah pragmatisme pada bagian dari penulis bahasa
Caleth
5
@ Caleth: Dan seluruh poin saya adalah bahwa desain ini muncul sepanjang waktu, dan bahwa sama sekali tidak ada yang secara inheren curiga tentang desain yang saya tunjukkan, dan karenanya casting bukanlah bau kode.
Mehrdad
4
@Caleth saya tidak setuju. Bagi saya, bau kode berarti bahwa kodenya jelek atau, paling tidak, bisa diperbaiki.
Konrad Rudolph
6
@Mehrdad Pendapat Anda tampaknya bahwa kode bau harus menjadi kesalahan programmer aplikasi. Mengapa? Tidak setiap bau kode harus menjadi masalah aktual atau memiliki solusi. Bau kode menurut Martin Fowler hanyalah "indikasi permukaan yang biasanya terkait dengan masalah yang lebih dalam dalam sistem" object.Equalscocok dengan deskripsi itu dengan sangat baik (cobalah untuk memberikan kontrak yang setara dengan benar dalam superclass yang memungkinkan subkelas untuk mengimplementasikannya dengan benar - itu benar-benar non-sepele). Bahwa sebagai pemrogram aplikasi kita tidak dapat menyelesaikannya (dalam beberapa kasus kita dapat menghindarinya) adalah topik yang berbeda.
Voo
5
@Mehrdad Baiklah mari kita lihat apa yang dikatakan oleh salah satu desainer bahasa asli tentang Setara .. Object.Equals is horrid. Equality computation in C# is completely messed up(komentar Eric pada jawabannya). Sangat lucu bagaimana Anda tidak ingin mempertimbangkan kembali pendapat Anda, bahkan ketika salah satu perancang utama bahasa itu sendiri memberi tahu Anda bahwa Anda salah.
Voo
136

Downcasting tidak populer, mungkin bau kode

Saya tidak setuju. Downcasting sangat populer ; sejumlah besar program di dunia nyata berisi satu atau lebih downcast. Dan itu mungkin bukan bau kode. Ini jelas merupakan bau kode. Itu sebabnya operasi downcasting diperlukan untuk menjadi nyata dalam teks program . Ini agar Anda bisa lebih mudah memperhatikan aroma dan menghabiskan perhatian review kode di atasnya.

dalam keadaan apa [s] yang tepat untuk menulis kode yang downcasts?

Dalam keadaan apa pun di mana:

  • Anda memiliki 100% pengetahuan yang benar tentang fakta tentang tipe runtime dari sebuah ekspresi yang lebih spesifik daripada tipe kompilasi-waktu dari ekspresi, dan
  • Anda perlu memanfaatkan fakta itu untuk menggunakan kemampuan objek yang tidak tersedia pada tipe waktu kompilasi, dan
  • ini adalah penggunaan waktu dan upaya yang lebih baik untuk menulis para pemeran daripada untuk memperbaiki program untuk menghilangkan salah satu dari dua poin pertama.

Jika Anda bisa dengan murah merevisi sebuah program sehingga tipe runtime dapat dideduksi oleh kompiler, atau untuk merevisi program sehingga Anda tidak memerlukan kemampuan dari tipe yang lebih diturunkan, maka lakukanlah. Orang-orang yang tertekan ditambahkan ke bahasa untuk keadaan-keadaan di mana sulit dan mahal untuk dengan demikian memperbaiki program.

mengapa downcasting didukung oleh bahasa?

C # ditemukan oleh programmer pragmatis yang memiliki pekerjaan untuk dilakukan, untuk programmer pragmatis yang memiliki pekerjaan untuk dilakukan. Desainer C # bukanlah puritan OO. Dan sistem tipe C # tidak sempurna; oleh desain itu meremehkan pembatasan yang dapat ditempatkan pada jenis runtime dari suatu variabel.

Juga, downcasting sangat aman di C #. Kami memiliki jaminan kuat bahwa downcast akan diverifikasi pada saat runtime dan jika tidak dapat diverifikasi maka program melakukan hal yang benar dan crash. Ini luar biasa; itu berarti bahwa jika 100% pemahaman Anda yang benar tentang tipe semantik ternyata 99,99% benar, maka program Anda bekerja 99,99% dari waktu dan crash sisa waktu, bukannya berperilaku tak terduga dan merusak data pengguna 0,01% dari waktu .


LATIHAN: Setidaknya ada satu cara untuk menghasilkan downcast dalam C # tanpa menggunakan operator pemeran eksplisit. Bisakah Anda memikirkan skenario seperti itu? Karena ini juga merupakan bau kode yang potensial, menurut Anda faktor desain apa yang masuk ke dalam desain fitur yang dapat menghasilkan crash yang terputus-putus tanpa ada pemain nyata dalam kode tersebut?

Eric Lippert
sumber
101
Ingat poster-poster di sekolah menengah di dinding "Apa yang populer tidak selalu benar, apa yang benar tidak selalu populer?" Anda mengira mereka berusaha mencegah Anda dari narkoba atau hamil di sekolah menengah tetapi sebenarnya peringatan tentang bahaya hutang teknis.
corsiKa
14
@EricLippert, pernyataan foreach, tentu saja. Ini dilakukan sebelum IEnumerable generik, bukan?
Arturo Torres Sánchez
18
Penjelasan ini membuat saya senang. Sebagai seorang guru, saya sering ditanya mengapa C # dirancang dengan cara ini atau itu, dan jawaban saya sering didasarkan pada motivasi yang Anda dan kolega Anda bagikan di sini dan di blog Anda. Seringkali agak sulit untuk menjawab pertanyaan tindak lanjut "Tapi kenapayyyy ?!". Dan di sini saya menemukan jawaban tindak lanjut yang sempurna: "C # ditemukan oleh programmer pragmatis yang memiliki pekerjaan, untuk programmer pragmatis yang memiliki pekerjaan yang harus dilakukan.". :-) Terima kasih @EricLippert!
Zano
12
Selain itu: Jelas dalam komentar saya di atas saya bermaksud mengatakan bahwa kita memiliki downcast dari A ke B. Saya benar-benar tidak menyukai penggunaan "naik" dan "turun" dan "orang tua" dan "anak" ketika menavigasi hirarki kelas dan saya mendapatkannya salah sepanjang waktu dalam tulisan saya. Hubungan antara tipe-tipe ini adalah hubungan superset / subset, jadi mengapa harus ada arah naik atau turun yang terkait dengannya, saya tidak tahu. Dan bahkan jangan mulai dengan "orang tua". Orang tua dari Jerapah bukan Mamalia, orang tua Jerapah adalah Tuan dan Nyonya Jerapah.
Eric Lippert
9
Object.Equalsadalah mengerikan . Perhitungan kesetaraan dalam C # benar - benar kacau , terlalu kacau untuk dijelaskan dalam komentar. Ada begitu banyak cara untuk mewakili kesetaraan; sangat mudah untuk membuatnya tidak konsisten; itu sangat mudah, pada kenyataannya diharuskan untuk melanggar sifat-sifat yang disyaratkan dari operator kesetaraan (simetri, refleksivitas dan transitivitas). Apakah saya merancang sistem tipe dari awal hari ini tidak akan ada Equals(atau GetHashcodeatau ToString) Objectsama sekali.
Eric Lippert
33

Penangan acara biasanya memiliki tanda tangan MethodName(object sender, EventArgs e). Dalam beberapa kasus mungkin untuk menangani acara tanpa memperhatikan apa jenisnya sender, atau bahkan tanpa menggunakan sendersama sekali, tetapi dalam kasus lain senderharus dilemparkan ke jenis yang lebih spesifik untuk menangani acara tersebut.

Misalnya, Anda mungkin memiliki dua TextBoxdan Anda ingin menggunakan satu delegasi untuk menangani suatu acara dari masing-masing. Kemudian Anda akan perlu untuk membuang senderke TextBoxsehingga Anda bisa mengakses sifat yang diperlukan untuk menangani acara:

private void TextBox_TextChanged(object sender, EventArgs e)
{
   TextBox box = (TextBox)sender;
   box.BackColor = string.IsNullOrEmpty(box.Text) ? Color.Red : Color.White;
}

Ya, dalam contoh ini, Anda dapat membuat subkelas Anda sendiri TextBoxyang melakukan ini secara internal. Namun, tidak selalu praktis atau mungkin.

mmathis
sumber
2
Terima kasih, itu contoh yang bagus. The TextChangedevent adalah anggota Control- saya bertanya-tanya mengapa sendertidak dari jenis Controlbukan jenis object? Saya juga bertanya-tanya apakah (secara teoritis) kerangka kerja dapat mendefinisikan ulang acara untuk setiap subkelas (sehingga misalnya TextBoxdapat memiliki versi baru dari acara tersebut, menggunakan TextBoxsebagai jenis pengirim) ... yang mungkin (atau mungkin tidak) memerlukan downcasting ( to TextBox) di dalam TextBoximplementasi (untuk mengimplementasikan tipe acara baru), tetapi akan menghindari keharusan downcast dalam event handler kode aplikasi.
ChrisW
3
Ini dianggap dapat diterima karena sulit untuk menggeneralisasi penanganan acara jika setiap acara memiliki metode tanda tangan sendiri. Meskipun saya kira itu adalah batasan yang diterima daripada sesuatu yang dianggap praktik terbaik karena alternatifnya sebenarnya lebih merepotkan. Jika hal itu mungkin untuk memulai dengan TextBox senderdaripada object sendertanpa terlalu rumit kode, saya yakin hal itu akan dilakukan.
Neil
6
@Neil Sistem acara secara khusus dibuat untuk memungkinkan penerusan potongan data sewenang-wenang ke objek sewenang-wenang. Itu hampir tidak mungkin dilakukan tanpa pemeriksaan runtime untuk ketepatan jenis.
Joker_vD
@ Joker_vD Idealnya, API tentu saja akan mendukung tanda tangan panggilan balik yang sangat diketik menggunakan kontravarian umum. Fakta bahwa .NET (sangat) tidak melakukan ini hanya karena fakta bahwa obat generik dan kovarian diperkenalkan kemudian. - Dengan kata lain, downcasting di sini (dan, umumnya, di tempat lain) diperlukan karena kekurangan dalam bahasa / API, bukan karena itu pada dasarnya ide yang bagus.
Konrad Rudolph
@KonradRudolph Tentu, tetapi bagaimana Anda menyimpan acara dengan tipe yang sewenang-wenang dalam antrian acara? Apakah Anda hanya menyingkirkan antrian dan pergi untuk pengiriman langsung?
Joker_vD
17

Anda perlu downcasting ketika sesuatu memberi Anda supertype dan Anda perlu menanganinya secara berbeda tergantung pada subtipe.

decimal value;
Donation d = user.getDonation();
if (d is CashDonation) {
     value = ((CashDonation)d).getValue();
}
if (d is ItemDonation) {
     value = itemValueEstimator.estimateValueOf(((ItemDonation)d).getItem());
}
System.out.println("Thank you for your generous donation of $" + value);

Tidak, ini baunya tidak enak. Dalam dunia yang sempurna Donationakan memiliki metode abstrak getValuedan setiap subtipe implementasi akan memiliki implementasi yang tepat.

Tetapi bagaimana jika kelas-kelas ini dari perpustakaan Anda tidak bisa atau tidak ingin berubah? Maka tidak ada pilihan lain.

Philipp
sumber
Ini sepertinya waktu yang tepat untuk menggunakan pola pengunjung. Atau dynamickata kunci yang mencapai hasil yang sama.
user2023861
3
@ user2023861 Tidak, saya pikir pola pengunjung tergantung pada kerja sama dari subkelas Donasi - yaitu, Donasi perlu mendeklarasikan abstrak void accept(IDonationVisitor visitor), yang diimplementasikan oleh subkelasnya dengan memanggil metode spesifik (misalnya kelebihan beban) IDonationVisitor.
ChrisW
@ Chris, Anda benar tentang itu. Tanpa kerja sama, Anda masih bisa melakukannya menggunakan dynamickata kunci.
user2023861
Dalam kasus khusus ini, Anda dapat menambahkan metode taksiran Nilai ke Donasi.
user253751
@ user2023861: dynamicmasih downcasting, hanya lebih lambat.
Mehrdad
12

Untuk menambah jawaban Eric Lippert karena saya tidak bisa berkomentar ...

Anda sering dapat menghindari downcasting dengan refactoring API untuk menggunakan obat generik. Tetapi obat generik tidak ditambahkan ke bahasa sampai versi 2.0 . Jadi, bahkan jika kode Anda sendiri tidak perlu mendukung versi bahasa kuno, Anda mungkin menemukan diri Anda menggunakan kelas-kelas lama yang tidak parameter. Sebagai contoh, beberapa kelas mungkin didefinisikan untuk membawa payload tipe Object, yang Anda dipaksa untuk melemparkan ke tipe yang Anda tahu sebenarnya.

TKK
sumber
Memang, orang mungkin mengatakan bahwa obat generik di Java atau C # pada dasarnya hanya pembungkus yang aman di sekitar menyimpan objek superclass dan downcasting ke subclass yang benar (diperiksa kompiler) sebelum menggunakan elemen lagi. (Tidak seperti templat C ++, yang menulis ulang kode untuk selalu menggunakan subclass itu sendiri dan dengan demikian menghindari downcast - yang dapat meningkatkan kinerja memori, jika sering dengan mengorbankan waktu kompilasi dan ukuran yang dapat dieksekusi.)
leftaroundabout
4

Ada pertukaran antara bahasa statis dan diketik secara dinamis. Pengetikan statis memberi kompiler banyak informasi untuk dapat membuat jaminan yang agak kuat tentang keamanan (bagian dari) program. Namun, hal ini berbiaya, karena Anda tidak hanya perlu tahu bahwa program Anda benar, tetapi Anda harus menulis kode yang sesuai untuk meyakinkan kompiler bahwa ini adalah masalahnya. Dengan kata lain, membuat klaim lebih mudah daripada membuktikannya.

Ada konstruksi "tidak aman" yang membantu Anda membuat pernyataan yang tidak terbukti ke kompiler. Misalnya, panggilan tanpa syarat ke Nullable.Value, downcast tanpa syarat, dynamicobjek, dll. Mereka memungkinkan Anda untuk mengajukan klaim ("Saya menyatakan bahwa objek aadalah String, jika saya salah, melempar InvalidCastException") tanpa perlu membuktikannya. Ini dapat berguna dalam kasus-kasus di mana membuktikannya secara signifikan lebih sulit daripada bermanfaat.

Menyalahgunakan ini berisiko, itulah sebabnya mengapa notasi downcast eksplisit ada dan wajib; itu garam sintaksis dimaksudkan untuk menarik perhatian operasi yang tidak aman. Bahasa tersebut dapat diimplementasikan dengan downcasting implisit (di mana jenis yang disimpulkan tidak ambigu), tetapi itu akan menyembunyikan operasi yang tidak aman ini, yang tidak diinginkan.

Alexander
sumber
Saya kira saya bertanya, kemudian, untuk beberapa contoh di mana / kapan diperlukan atau diinginkan (yaitu praktik yang baik) untuk membuat "pernyataan yang tidak terbukti" semacam ini.
ChrisW
1
Bagaimana dengan casting hasil operasi refleksi? stackoverflow.com/a/3255716/3141234
Alexander
3

Downcasting dianggap buruk karena beberapa alasan. Terutama saya pikir karena itu anti-OOP.

OOP akan sangat menyukainya jika Anda tidak pernah harus tertunduk karena '' raison-d'etre '' adalah bahwa polimorfisme berarti Anda tidak perlu pergi

if(object is X)
{
    //do the thing we do with X's
}
else
{
    //of the thing we do with Y's
}

kamu lakukan saja

x.DoThing()

dan kode secara otomatis melakukan hal yang benar.

Ada beberapa alasan 'sulit' untuk tidak tertunduk:

  • Dalam C ++ lambat.
  • Anda mendapatkan kesalahan runtime jika Anda memilih jenis yang salah.

Tetapi alternatif untuk downcasting dalam beberapa skenario bisa sangat jelek.

Contoh klasiknya adalah pemrosesan pesan, di mana Anda tidak ingin menambahkan fungsi pemrosesan ke objek, tetapi simpan di pengolah pesan. Saya kemudian memiliki satu ton MessageBaseClassdalam array untuk diproses, tetapi saya juga membutuhkan masing-masing dengan subtipe untuk pemrosesan yang benar.

Anda dapat menggunakan Double Dispatch untuk menyelesaikan masalah ( https://en.wikipedia.org/wiki/Double_dispatch ) ... Tetapi itu juga memiliki masalah. Atau Anda bisa downcast untuk beberapa kode sederhana dengan risiko alasan-alasan sulit itu.

Tapi ini sebelum Generik ditemukan. Sekarang Anda dapat menghindari downcasting dengan menyediakan jenis yang detailnya ditentukan kemudian.

MessageProccesor<T> dapat memvariasikan parameter metode dan mengembalikan nilai menurut tipe yang ditentukan tetapi tetap menyediakan fungsionalitas umum

Tentu saja tidak ada yang memaksa Anda untuk menulis kode OOP dan ada banyak fitur bahasa yang disediakan tetapi disukai, seperti refleksi.

Ewan
sumber
1
Saya ragu itu lambat di C ++, terutama jika Anda static_castbukan dynamic_cast.
ChrisW
"Pemrosesan pesan" - Saya menganggapnya sebagai makna, mis. Casting lParamke sesuatu yang spesifik. Tapi saya tidak yakin itu contoh C # yang bagus.
ChrisW
3
@ ChrisW - yah, ya, static_castselalu cepat ... tetapi tidak dijamin tidak akan gagal dengan cara yang tidak ditentukan jika Anda melakukan kesalahan dan tipenya tidak seperti yang Anda harapkan.
Jules
@ Jules: Itu sepenuhnya tidak penting.
Mehrdad
@Madrdad, itu intinya. untuk melakukan yang setara dengan c # cast dalam c ++ lambat. dan inilah alasan tradisional menentang casting. static_cast alternatif tidak setara dan dianggap sebagai pilihan yang lebih buruk karena perilaku yang tidak terdefinisi
Ewan
0

Selain semua yang dikatakan sebelumnya, bayangkan properti Tag yang bertipe objek. Ini memberikan cara bagi Anda untuk menyimpan objek pilihan Anda di objek lain untuk digunakan nanti yang Anda butuhkan. Anda perlu downcast properti ini.

Secara umum, tidak menggunakan sesuatu sampai hari ini tidak selalu merupakan indikasi sesuatu yang tidak berguna ;-)

keping
sumber
Ya lihat misalnya Apa gunanya properti Tag di .net . Dalam salah satu jawaban di sana, seseorang menulis, saya biasa menggunakannya untuk memasukkan instruksi kepada pengguna di aplikasi Windows Forms. Ketika acara GotFocus kontrol dipicu, properti instruksi Label.Text diberi nilai properti Tag kontrol saya yang berisi string instruksi. Saya kira cara alternatif untuk 'memperpanjang' Control(alih-alih menggunakan object Tagproperti) adalah dengan membuat Dictionary<Control, string>label untuk setiap kontrol.
ChrisW
1
Saya suka jawaban ini karena Tagmerupakan properti publik dari kelas .Net framework, yang menunjukkan bahwa Anda (kurang lebih) seharusnya menggunakannya.
ChrisW
@ChrisW: Bukan untuk mengatakan kesimpulan yang salah (atau kanan), tetapi perhatikan bahwa itu alasan ceroboh, karena ada banyak fungsi NET publik yang merupakan usang (katakanlah, System.Collections.ArrayList) atau usang (katakanlah, IEnumerator.Reset).
Mehrdad
0

Penggunaan downcasting yang paling umum dalam pekerjaan saya adalah karena beberapa orang idiot yang melanggar prinsip Pergantian Liskov.

Bayangkan ada antarmuka di beberapa lib pihak ketiga.

public interface Foo
{
     void SayHello();
     void SayGoodbye();
 }

Dan 2 kelas yang mengimplementasikannya. Bardan Qux. Barberperilaku baik.

public class Bar
{
    void SayHello()
    {
        Console.WriteLine(“Bar says hello.”);
    }
    void SayGoodbye()
    {
         Console.WriteLine(“Bar says goodbye”);
    }
}

Tetapi Quxtidak berperilaku baik.

public class Qux
{
    void SayHello()
    {
        Console.WriteLine(“Qux says hello.”);
    }
    void SayGoodbye()
    {
        throw new NotImplementedException();
    }
}

Baiklah ... sekarang saya tidak punya pilihan. Saya harus mengetik cek dan (mungkin) downcast untuk menghindari program saya terhenti.

Bebek karet
sumber
1
Tidak benar untuk contoh khusus ini. Anda bisa menangkap NotImplementedException saat memanggil SayGoodbye.
Per von Zweigbergk
Ini mungkin contoh yang terlalu disederhanakan, tetapi bekerja dengan beberapa .Net API yang lebih lama dan Anda akan mengalami situasi ini. Terkadang cara termudah untuk menulis kode adalah dengan cara aman var qux = foo as Qux;.
RubberDuck
0

Contoh dunia nyata lainnya adalah WPF VisualTreeHelper. Ini menggunakan downcast untuk melemparkan DependencyObjectke Visualdan Visual3D. Misalnya, VisualTreeHelper.GetParent . Downcast terjadi di VisualTreeUtils.AsVisualHelper :

private static bool AsVisualHelper(DependencyObject element, out Visual visual, out Visual3D visual3D)
{
    Visual elementAsVisual = element as Visual;

    if (elementAsVisual != null)
    {
        visual = elementAsVisual;
        visual3D = null;
        return true;
    }

    Visual3D elementAsVisual3D = element as Visual3D;

    if (elementAsVisual3D != null)
    {
        visual = null;
        visual3D = elementAsVisual3D;
        return true;
    }            

    visual = null;
    visual3D = null;
    return false;
}
zwcloud
sumber