Dalam C #, out
kata kunci dapat digunakan dalam dua cara berbeda.
Sebagai pengubah parameter di mana argumen dilewatkan oleh referensi
class OutExample { static void Method(out int i) { i = 44; } static void Main() { int value; Method(out value); // value is now 44 } }
Sebagai pengubah parameter tipe untuk menentukan kovarians .
// Covariant interface. interface ICovariant<out R> { } // Extending covariant interface. interface IExtCovariant<out R> : ICovariant<R> { } // Implementing covariant interface. class Sample<R> : ICovariant<R> { } class Program { static void Test() { ICovariant<Object> iobj = new Sample<Object>(); ICovariant<String> istr = new Sample<String>(); // You can assign istr to iobj because // the ICovariant interface is covariant. iobj = istr; } }
Pertanyaan saya adalah: mengapa?
Bagi seorang pemula, hubungan antara keduanya tampaknya tidak intuitif . Penggunaan dengan obat generik tampaknya tidak ada hubungannya dengan melewati referensi.
Saya pertama kali belajar apa out
yang terkait dengan melewati argumen dengan referensi, dan ini menghambat pemahaman saya tentang penggunaan mendefinisikan kovarians dengan obat generik.
Apakah ada koneksi antara penggunaan ini yang saya lewatkan?
c#
terminology
language-design
keywords
Rowan Freeman
sumber
sumber
System.Func<in T, out TResult>
delegasi .Jawaban:
Ada koneksi, namun agak longgar. Dalam C # kata kunci ´in´ dan ´out´ seperti namanya menyarankan untuk input dan output. Ini sangat jelas dalam hal parameter output, tetapi kurang bersih apa yang harus dilakukan dengan parameter template.
Mari kita lihat prinsip substitusi Liskov :
Lihat bagaimana contravariance dikaitkan dengan input dan covariance dikaitkan dengan output? Dalam C # jika Anda menandai variabel templat dengan
out
untuk membuatnya kovarian, tetapi harap dicatat Anda hanya dapat melakukan ini jika parameter tipe yang disebutkan hanya muncul sebagai output (tipe pengembalian fungsi). Jadi yang berikut ini tidak valid:Sama jika Anda menandai parameter tipe dengan
in
, itu berarti Anda hanya dapat menggunakannya sebagai input (parameter fungsi). Jadi yang berikut ini tidak valid:Jadi untuk meringkas, hubungan dengan
out
kata kunci adalah bahwa dengan parameter fungsi itu berarti bahwa itu adalah parameter output , dan untuk tipe parameter itu berarti bahwa tipe tersebut hanya digunakan dalam konteks output .System.Func
juga merupakan contoh yang baik apa rwong disebutkan dalam komentarnya. DalamSystem.Func
semua parameter input denganin
, dan parameter output denganout
. Alasannya persis seperti yang saya jelaskan.sumber
@ Gábor telah menjelaskan koneksi (contravariance untuk semua yang masuk "in", covariance untuk semua yang keluar "out"), tetapi mengapa menggunakan kembali kata kunci sama sekali?
Yah, kata kunci sangat mahal. Anda tidak dapat menggunakannya sebagai pengidentifikasi dalam program Anda. Tetapi hanya ada begitu banyak kata dalam bahasa Inggris. Jadi, terkadang Anda mengalami konflik, dan Anda harus dengan canggung mengganti nama variabel, metode, bidang, properti, kelas, antarmuka, atau struct untuk menghindari bentrok dengan kata kunci. Misalnya, jika Anda membuat model sebuah sekolah, apa yang Anda sebut kelas? Anda tidak dapat menyebutnya kelas, karena
class
kata kunci!Menambahkan kata kunci ke bahasa bahkan lebih mahal. Itu pada dasarnya membuat semua kode yang menggunakan kata kunci ini sebagai pengidentifikasi ilegal, melanggar kompatibilitas mundur di semua tempat.
Kata kunci
in
danout
sudah ada, sehingga hanya bisa digunakan kembali.Mereka dapat menambahkan kata kunci kontekstual yang hanya kata kunci dalam konteks daftar parameter tipe, tetapi kata kunci apa yang akan mereka pilih?
covariant
dancontravariant
?+
dan-
(seperti yang dilakukan Scala, misalnya)?super
danextends
seperti Jawa? Bisakah Anda mengingat dari atas kepala Anda parameter mana yang kovarian dan contravarian?Dengan solusi saat ini, ada mnemonik yang bagus: parameter tipe output mendapatkan
out
kata kunci, parameter tipe input mendapatkanin
kata kunci. Perhatikan simetri yang bagus dengan parameter metode: parameter output mendapatkanout
kata kunci, parameter input mendapatkanin
kata kunci (well, sebenarnya, tidak ada kata kunci sama sekali, karena input adalah default, tetapi Anda mendapatkan ide).[Catatan: jika Anda melihat histori edit, Anda akan melihat bahwa saya awalnya mengubah keduanya dalam kalimat pengantar saya. Dan saya bahkan mendapat upvote selama waktu itu! Ini hanya untuk menunjukkan betapa pentingnya mnemonik itu.]
sumber
interface Accepter<in T> { void Accept(T it);};
, suatuAccepter<Foo<T>>
akan menerimaT
sebagai parameter input jikaFoo<T>
menerimanya sebagai parameter output, dan sebaliknya. Jadi, kontra- variasi. Sebaliknya,interface ISupplier<out T> { T get();};
suatuSupplier<Foo<T>>
varianFoo
memiliki jenis varian apa pun - dengan demikian co- varians.