Bagikan melalui


10 Konversi

10.1 Umum

Konversi menyebabkan ekspresi dikonversi ke, atau diperlakukan sebagai, jenis tertentu; dalam kasus sebelumnya konversi dapat melibatkan perubahan representasi. Konversi dapat bersifat implisit atau eksplisit, dan ini menentukan apakah cast eksplisit diperlukan.

Contoh: Misalnya, konversi dari jenis int ke jenis long bersifat implisit, sehingga ekspresi jenis int dapat secara implisit diperlakukan sebagai jenis long. Konversi yang berlawanan, dari jenis long ke jenis int, eksplisit dan sehingga diperlukan pemeran eksplisit.

int a = 123;
long b = a;      // implicit conversion from int to long
int c = (int) b; // explicit conversion from long to int

contoh akhir

Beberapa konversi didefinisikan oleh bahasa. Program juga dapat menentukan konversi mereka sendiri (§10,5).

Beberapa konversi dalam bahasa ditentukan dari ekspresi ke jenis, yang lain dari jenis ke jenis. Konversi dari jenis berlaku untuk semua ekspresi yang memiliki jenis tersebut.

Contoh:

enum Color { Red, Blue, Green }

// The expression 0 converts implicitly to enum types
Color c0 = 0;

// Other int expressions need explicit conversion
Color c1 = (Color)1;

// Conversion from null expression (no type) to string
string x = null;

// Conversion from lambda expression to delegate type
Func<int, int> square = x => x * x;

contoh akhir

10.2 Konversi implisit

10.2.1 Umum

Konversi berikut diklasifikasikan sebagai konversi implisit:

Konversi implisit dapat terjadi dalam berbagai situasi, termasuk pemanggilan anggota fungsi (§12.6.6), ekspresi cast (§12.9.7), dan penugasan (§12,21).

Konversi implisit yang telah ditentukan sebelumnya selalu berhasil dan tidak pernah menyebabkan pengecualian dilemparkan.

Catatan: Konversi implisit yang ditentukan pengguna yang dirancang dengan benar juga harus menunjukkan karakteristik ini. catatan akhir

Untuk tujuan konversi, jenis object dan dynamic dapat dikonversi identitas (§10.2.2).

Namun, konversi dinamis (§10.2.10) hanya berlaku untuk ekspresi jenis dynamic (§8.2.4).

10.2.2 Konversi identitas

Konversi identitas dikonversi dari jenis apa pun ke jenis yang sama atau jenis yang setara pada runtime. Salah satu alasan konversi ini ada sehingga jenis T atau ekspresi jenis T dapat dikatakan dapat dikonversi ke T dirinya sendiri. Konversi identitas berikut ada:

  • Antara T dan T, untuk semua jenis T.
  • Antara T dan T? untuk jenis Treferensi apa pun .
  • Antara object dan dynamic.
  • Antara semua jenis tuple dengan aritas yang sama, dan jenis konstruksi yang sesuai ValueTuple<...> , ketika konversi identitas ada di antara setiap pasangan jenis elemen yang sesuai.
  • Antara jenis yang dibangun dari jenis generik yang sama di mana ada konversi identitas antara setiap argumen jenis yang sesuai.

Contoh: Berikut ini menggambarkan sifat rekursif dari aturan ketiga:

(int a , string b) t1 = (1, "two");
(int c, string d) t2 = (3, "four");

// Identity conversions exist between
// the types of t1, t2, and t3.
var t3 = (5, "six");
t3 = t2;
t2 = t1;

var t4 = (t1, 7);
var t5 = (t2, 8);

// Identity conversions exist between
// the types of t4, t5, and t6.
var t6 =((8, "eight"), 9);
t6 = t5;
t5 = t4;

Jenis tuple t1, t2 dan t3 semuanya memiliki dua elemen: diikuti int oleh string. Jenis elemen tuple dapat sendiri dengan tuple, seperti dalam t4, t5, dan t6. Konversi identitas ada di antara setiap pasangan jenis elemen yang sesuai, termasuk tuple berlapis, oleh karena itu konversi identitas ada di antara jenis tuple t4, , t5dan t6.

contoh akhir

Semua konversi identitas bersifat simetris. Jika konversi identitas ada dari T₁ ke T₂, maka konversi identitas ada dari T₂ ke T₁. Dua jenis dapat dikonversi identitas ketika konversi identitas ada di antara dua jenis.

Dalam kebanyakan kasus, konversi identitas tidak berpengaruh pada runtime. Namun, karena operasi floating point dapat dilakukan pada presisi yang lebih tinggi daripada yang ditentukan oleh jenisnya (§8.3.7), penugasan hasilnya dapat mengakibatkan hilangnya presisi, dan cast eksplisit dijamin untuk mengurangi presisi terhadap apa yang ditentukan oleh jenis (§12.9.7).

10.2.3 Konversi numerik implisit

Konversi numerik implisit adalah:

  • Dari sbyte ke short, int, long, float, double, atau decimal.
  • Dari byte ke short, ushort, int, uint, long, ulong, float, double, atau decimal.
  • Dari short ke int, long, float, double, atau decimal.
  • Dari ushort ke int, uint, long, ulong, float, double, atau decimal.
  • Dari int ke long, float, double, atau decimal.
  • Dari uint ke long, ulong, float, double, atau decimal.
  • Dari long ke float, double, atau decimal.
  • Dari ulong ke float, double, atau decimal.
  • Dari char ke ushort, int, uint, long, ulong, float, double, atau decimal.
  • Dari float sampai double.

Konversi dari int, , uintlong atau ulong ke float dan dari long atau ulong ke double dapat menyebabkan hilangnya presisi, tetapi tidak akan pernah menyebabkan hilangnya besaran. Konversi numerik implisit lainnya belum pernah kehilangan informasi apa pun.

Tidak ada konversi implisit yang telah ditentukan sebelumnya ke char jenis , sehingga nilai jenis integral lainnya tidak secara otomatis dikonversi ke jenis .char

10.2.4 Konversi enumerasi implisit

Konversi enumerasi implisit memungkinkan constant_expression (§12,23) dengan jenis bilangan bulat apa pun dan nilai nol yang akan dikonversi ke enum_type apa pun dan ke nullable_value_type yang jenis yang mendasarnya adalah enum_type. Dalam kasus terakhir, konversi dievaluasi dengan mengonversi ke enum_type yang mendasar dan membungkus hasilnya (§8.3.12).

10.2.5 Konversi string terinterpolasi implisit

Konversi string terinterpolasi implisit mengizinkan interpolated_string_expression (§12.8.3) untuk dikonversi ke System.IFormattable atau System.FormattableString (yang mengimplementasikan System.IFormattable). Ketika konversi ini diterapkan, nilai string tidak terdiri dari string terinterpolasi. Sebagai gantinya, instans System.FormattableString dibuat, seperti yang dijelaskan lebih lanjut dalam §12.8.3.

10.2.6 Konversi implisit nullable

Konversi implisit nullable adalah konversi nullable (§10.6.1) yang berasal dari konversi implisit yang telah ditentukan sebelumnya.

10.2.7 Konversi harfiah null

Konversi implisit ada dari null literal ke jenis referensi apa pun atau jenis nilai nullable. Konversi ini menghasilkan referensi null jika jenis target adalah jenis referensi, atau nilai null (§8.3.12) dari jenis nilai nullable yang diberikan.

10.2.8 Konversi referensi implisit

Konversi referensi implisit adalah:

  • Dari reference_type ke object dan dynamic.
  • Dari class_type Shingga class_type, yang disediakan T berasal dari S.
  • Dari class_typehingga interface_typeS, yang disediakan mengimplementasikan T.
  • Dari interface_type Shingga interface_type, yang disediakan T berasal dari S.
  • dengan jenis S elemen ke Sᵢ dengan jenis Telemen , asalkan semua hal berikut ini benar:
    • S dan T hanya berbeda dalam jenis elemen. Dengan kata lain, S dan T memiliki jumlah dimensi yang sama.
    • Konversi referensi implisit ada dari Sᵢ ke Tᵢ.
  • Dari jenis S[] array dimensi tunggal ke System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>, dan antarmuka dasarnya, asalkan ada konversi identitas atau referensi implisit dari S ke T.
  • Dari array_type apa pun hingga System.Array dan antarmuka yang diimplementasikannya.
  • Dari delegate_type apa pun hingga System.Delegate dan antarmuka yang diimplementasikannya.
  • Dari literal null (§6.4.5.7) hingga jenis referensi apa pun.
  • Dari reference_type apa pun
  • Dari reference_type apa pun
  • Konversi implisit yang melibatkan parameter jenis yang dikenal sebagai jenis referensi. Lihat §10.2.12 untuk detail selengkapnya tentang konversi implisit yang melibatkan parameter jenis.

Konversi referensi implisit adalah konversi antara reference_typeyang dapat terbukti selalu berhasil, dan karenanya tidak memerlukan pemeriksaan pada run-time.

Konversi referensi, implisit atau eksplisit, tidak pernah mengubah identitas referensial objek yang dikonversi.

Catatan: Dengan kata lain, sementara konversi referensi dapat mengubah jenis referensi, itu tidak pernah mengubah jenis atau nilai objek yang dirujuk. catatan akhir

10.2.9 Konversi Tinju

Konversi tinju memungkinkan value_type dikonversi secara implisit ke reference_type. Konversi tinju berikut ada:

  • Dari value_type apa pun
  • Dari value_type apa pun
  • Dari enum_type apa pun
  • Dari non_nullable_value_type apa pun hingga interface_type apa pun yang diterapkan oleh non_nullable_value_type.
  • Dari non_nullable_value_type apa pun
  • Dari non_nullable_value_type apa pun
  • Dari nullable_value_type apa pun ke reference_type mana pun di mana ada konversi tinju dari jenis nullable_value_type yang mendasar ke reference_type.
  • Dari parameter jenis yang tidak diketahui sebagai jenis referensi ke jenis apa pun sehingga konversi diizinkan oleh §10.2.12.

Tinju nilai jenis nilai yang tidak dapat diubah ke null terdiri dari mengalokasikan instans objek dan menyalin nilai ke dalam instans tersebut.

Tinju nilai nullable_value_type menghasilkan referensi null jika itu adalah nilai null (HasValue salah), atau hasil pembongkaran dan tinju nilai yang mendasar sebaliknya.

Catatan: Proses tinju dapat dibayangkan dalam hal keberadaan kelas tinju untuk setiap jenis nilai. Misalnya, pertimbangkan struct S untuk menerapkan antarmuka I, dengan kelas tinju yang disebut S_Boxing.

interface I
{
    void M();
}

struct S : I
{
    public void M() { ... }
}

sealed class S_Boxing : I
{
    S value;

    public S_Boxing(S value)
    {
        this.value = value;
    }

    public void M()
    {
        value.M();
    }
}

Tinju nilai v jenis S sekarang terdiri dari menjalankan ekspresi new S_Boxing(v) dan mengembalikan instans yang dihasilkan sebagai nilai dari jenis target konversi. Dengan demikian, pernyataan

S s = new S();
object box = s;

dapat dianggap mirip dengan:

S s = new S();
object box = new S_Boxing(s);

Jenis tinju yang dibayangkan yang dijelaskan di atas sebenarnya tidak ada. Sebagai gantinya, nilai berkotak jenis S memiliki jenis Sruntime , dan pemeriksaan jenis runtime menggunakan is operator dengan jenis nilai sebagai uji operand kanan apakah operand kiri adalah versi kotak dari operand kanan. Contohnya,

int i = 123;
object box = i;
if (box is int)
{
    Console.Write("Box contains an int");
}

akan menghasilkan yang berikut:

Box contains an int

Konversi tinju menyiratkan pembuatan salinan nilai yang dikotak. Ini berbeda dari konversi reference_type ke jenis object, di mana nilai terus mereferensikan instans yang sama dan hanya dianggap sebagai jenis objectyang kurang diturunkan . Misalnya, berikut ini

struct Point
{
    public int x, y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

class A
{
    void M() 
    {
        Point p = new Point(10, 10);
        object box = p;
        p.x = 20;
        Console.Write(((Point)box).x);
    }
}

akan menghasilkan nilai 10 pada konsol karena operasi tinju implisit yang terjadi dalam penugasan p menyebabkan box nilai p disalin. Telah Point dinyatakan sebagai class gantinya, nilai 20 akan menjadi output karena p dan box akan mereferensikan instans yang sama.

Analogi kelas tinju tidak boleh digunakan sebagai lebih dari alat bermanfaat untuk menggambarkan cara kerja tinju secara konseptual. Ada banyak perbedaan halus antara perilaku yang dijelaskan oleh spesifikasi ini dan perilaku yang akan mengakibatkan tinju diimplementasikan dengan tepat dengan cara ini.

catatan akhir

10.2.10 Konversi dinamis implisit

Konversi dinamis implisit ada dari ekspresi jenis dinamis ke jenis Tapa pun . Konversi terikat secara dinamis §12.3.3, yang berarti bahwa konversi implisit akan dicari pada run-time dari jenis run-time ekspresi ke T. Jika tidak ada konversi yang ditemukan, pengecualian run-time akan dilemparkan.

Konversi implisit ini tampaknya melanggar saran di awal §10.2 bahwa konversi implisit tidak boleh menyebabkan pengecualian. Namun, itu bukan konversi itu sendiri, tetapi temuan konversi yang menyebabkan pengecualian. Risiko pengecualian run-time melekat dalam penggunaan pengikatan dinamis. Jika pengikatan dinamis konversi tidak diinginkan, ekspresi dapat terlebih dahulu dikonversi ke object, lalu ke jenis yang diinginkan.

Contoh: Berikut ini menggambarkan konversi dinamis implisit:

object o = "object";
dynamic d = "dynamic";
string s1 = o;         // Fails at compile-time – no conversion exists
string s2 = d;         // Compiles and succeeds at run-time
int i = d;             // Compiles but fails at run-time – no conversion exists

Penugasan ke s2 dan i keduanya menggunakan konversi dinamis implisit, di mana pengikatan operasi ditangguhkan hingga run-time. Pada run-time, konversi implisit dicari dari jenis drun-time (string) ke jenis target. Konversi ditemukan tetapi string tidak ke int.

contoh akhir

10.2.11 Konversi ekspresi konstanta implisit

Konversi ekspresi konstanta implisit mengizinkan konversi berikut:

  • Jenis
  • Constant_expression jenis long dapat dikonversi ke jenis ulong, asalkan nilai constant_expression tidak negatif.

10.2.12 Konversi implisit yang melibatkan parameter jenis

yang dikenal sebagai jenis referensi (T), konversi referensi implisit berikut (§10.2.8) ada:

  • Dari ke kelas Tdasar yang efektif , dari C ke kelas dasar apa pun , Tdan dari C ke antarmuka apa pun yang diimplementasikan oleh T.C
  • Dari T ke interface_typeI dalam Tset antarmuka efektif dan dari T ke antarmuka dasar apa pun dari I.
  • Dari T ke parameter U jenis yang disediakan yang T bergantung pada U (§15.2.5).

    Catatan: Karena T dikenal sebagai jenis referensi, dalam lingkup T, jenis U run-time akan selalu menjadi jenis referensi, bahkan jika U tidak diketahui sebagai jenis referensi pada waktu kompilasi. catatan akhir

  • Dari harfiah null (§6.4.5.7) hingga T.

yang T diketahui sebagai jenis referensi §15.2.5, konversi berikut yang melibatkan dianggap sebagai konversi tinju (T) pada waktu kompilasi. Pada run-time, jika T adalah jenis nilai, konversi dijalankan sebagai konversi tinju. Pada run-time, jika T merupakan jenis referensi, konversi dijalankan sebagai konversi referensi implisit atau konversi identitas.

  • Dari ke kelas Tdasar yang efektif , dari C ke kelas dasar apa pun , Tdan dari C ke antarmuka apa pun yang diimplementasikan oleh T.C

    Catatan: C akan menjadi salah satu jenis System.Object, , System.ValueTypeatau System.Enum (jika tidak T , akan diketahui sebagai jenis referensi). catatan akhir

  • Dari T ke interface_typeI dalam Tset antarmuka efektif dan dari T ke antarmuka dasar apa pun dari I.

yang T diketahui sebagai jenis referensi, ada konversi implisit dari ke parameter T jenis yang disediakan U tergantung pada T. Pada run-time, jika T adalah jenis nilai dan U merupakan jenis referensi, konversi dijalankan sebagai konversi tinju. Pada run-time, jika dan TU merupakan jenis nilai, maka T dan U harus jenis yang sama dan tidak ada konversi yang dilakukan. Pada run-time, jika T adalah jenis referensi, maka U tentu juga merupakan jenis referensi dan konversi dijalankan sebagai konversi referensi implisit atau konversi identitas (§15.2.5).

Konversi implisit lebih lanjut berikut ada untuk parameter Tjenis tertentu :

  • Dari T ke jenis S referensi jika memiliki konversi implisit ke jenis S₀ referensi dan S₀ memiliki konversi identitas ke S. Pada run-time, konversi dijalankan dengan cara yang sama seperti konversi ke S₀.
  • Dari T ke jenis I antarmuka jika memiliki konversi implisit ke jenis I₀antarmuka , dan I₀ dapat dikonversi varians ke I (§18.2.3.3). Pada run-time, jika T adalah jenis nilai, konversi dijalankan sebagai konversi tinju. Jika tidak, konversi dijalankan sebagai konversi referensi implisit atau konversi identitas.

Dalam semua kasus, aturan memastikan bahwa konversi dijalankan sebagai konversi tinju jika dan hanya jika pada run-time konversi berasal dari jenis nilai ke jenis referensi.

10.2.13 Konversi tuple implisit

Konversi implisit ada dari ekspresi E tuple ke jenis T tuple jika E memiliki aritas yang sama dengan T dan konversi implisit ada dari setiap elemen ke E jenis elemen yang sesuai di T. Konversi dilakukan dengan membuat instans jenis Tyang System.ValueTuple<...> sesuai, dan menginisialisasi setiap bidangnya secara berurutan dari kiri ke kanan dengan mengevaluasi ekspresi Eelemen tuple yang sesuai , mengonversinya ke jenis elemen yang sesuai menggunakan T konversi implisit yang ditemukan, dan menginisialisasi bidang dengan hasilnya.

Jika nama elemen dalam ekspresi tuple tidak cocok dengan nama elemen yang sesuai dalam jenis tuple, peringatan akan dikeluarkan.

Contoh:

(int, string) t1 = (1, "One");
(byte, string) t2 = (2, null);
(int, string) t3 = (null, null);        // Error: No conversion
(int i, string s) t4 = (i: 4, "Four");
(int i, string) t5 = (x: 5, s: "Five"); // Warning: Names are ignored

Deklarasi t1, t2, t4 dan t5 semuanya valid, karena konversi implisit ada dari ekspresi elemen ke jenis elemen yang sesuai. Deklarasi t3 tidak valid, karena tidak ada konversi dari null ke int. Deklarasi t5 menyebabkan peringatan karena nama elemen dalam ekspresi tuple berbeda dari yang ada di jenis tuple.

contoh akhir

10.2.14 Konversi implisit yang ditentukan pengguna

Konversi implisit yang ditentukan pengguna terdiri dari konversi implisit standar opsional, diikuti dengan eksekusi operator konversi implisit yang ditentukan pengguna, diikuti oleh konversi implisit standar opsional lainnya. Aturan yang tepat untuk mengevaluasi konversi implisit yang ditentukan pengguna dijelaskan dalam §10.5.4.

10.2.15 Konversi fungsi anonim dan konversi grup metode

Fungsi anonim dan grup metode tidak memiliki jenis dalam dan dari diri mereka sendiri, tetapi mungkin secara implisit dikonversi untuk mendelegasikan jenis. Selain itu, beberapa ekspresi lambda dapat dikonversi secara implisit ke jenis pohon ekspresi. Konversi fungsi anonim dijelaskan secara lebih rinci dalam §10,7 dan konversi grup metode dalam §10,8.

10.2.16 Konversi literal default

Konversi implisit ada dari default_literal (§12.8.21) ke jenis apa pun. Konversi ini menghasilkan nilai default (§9,3) dari jenis yang disimpulkan.

10.2.17 Konversi lemparan implisit

Meskipun ekspresi lemparan tidak memiliki jenis, ekspresi mungkin dikonversi secara implisit ke jenis apa pun.

10.3 Konversi eksplisit

10.3.1 Umum

Konversi berikut diklasifikasikan sebagai konversi eksplisit:

  • Semua konversi implisit (§10.2)
  • Konversi numerik eksplisit (§10.3.2)
  • Konversi enumerasi eksplisit (§10.3.3)
  • Konversi nullable eksplisit (§10.3.4)
  • Konversi tuple eksplisit (§10.3.6)
  • Konversi referensi eksplisit (§10.3.5)
  • Konversi antarmuka eksplisit
  • Membatalkan konversi kotak (§10.3.7)
  • Konversi parameter jenis eksplisit (§10.3.8)
  • Konversi eksplisit yang ditentukan pengguna (§10.3.9)

Konversi eksplisit dapat terjadi dalam ekspresi pemeran (§12.9.7).

Kumpulan konversi eksplisit mencakup semua konversi implisit.

Catatan: Ini, misalnya, memungkinkan cast eksplisit digunakan ketika konversi identitas implisit ada, untuk memaksa pemilihan metode tertentu kelebihan beban. catatan akhir

Konversi eksplisit yang bukan konversi implisit adalah konversi yang tidak dapat dibuktikan selalu berhasil, konversi yang diketahui mungkin kehilangan informasi, dan konversi di seluruh domain jenis yang cukup berbeda untuk merit notasi eksplisit.

10.3.2 Konversi numerik eksplisit

Konversi numerik eksplisit adalah konversi dari numeric_type ke numeric_type lain yang konversi numerik implisitnya (§10.2.3) belum ada:

  • Dari sbyte ke byte, ushort, uint, ulong, atau char.
  • Dari byte ke sbyte atau char.
  • Dari short ke sbyte, byte, ushort, uint, ulong, atau char.
  • Dari ushort ke sbyte, byte, short, atau char.
  • Dari int ke sbyte, byte, short, ushort, uint, ulong, atau char.
  • Dari uint ke sbyte, byte, short, ushort, int, atau char.
  • Dari long ke sbyte, byte, short, ushort, int, uint, ulong, atau char.
  • Dari ulong ke sbyte, byte, short, ushort, int, uint, long, atau char.
  • Dari char ke sbyte, byte, atau short.
  • Dari float ke sbyte, byte, short, ushort, int, uint, long, ulong, , char, atau decimal.
  • Dari double ke sbyte, byte, short, ushort, int, uint, long, ulong, char, , float, atau decimal.
  • Dari decimal ke sbyte, byte, short, ushort, int, uint, long, ulong, char, , float, atau double.

Karena konversi eksplisit mencakup semua konversi numerik implisit dan eksplisit, selalu dimungkinkan untuk mengonversi dari numeric_type apa pun ke numeric_type lain menggunakan ekspresi pemeran (§12.9.7).

Konversi numerik eksplisit mungkin kehilangan informasi atau mungkin menyebabkan pengecualian dilemparkan. Konversi numerik eksplisit diproses sebagai berikut:

  • Untuk konversi dari jenis integral ke jenis integral lain, pemrosesan tergantung pada konteks pemeriksaan luapan (§12.8.20) di mana konversi terjadi:
    • checked Dalam konteks, konversi berhasil jika nilai operand sumber berada dalam rentang jenis tujuan, tetapi melemparkan System.OverflowException jika nilai operand sumber berada di luar rentang jenis tujuan.
    • Dalam konteks unchecked , konversi selalu berhasil, dan berlanjut sebagai berikut.
      • Jika jenis sumber lebih besar dari jenis tujuan, maka nilai sumber dipotong dengan membuang bit "ekstra" yang paling signifikan. Hasilnya kemudian diperlakukan sebagai nilai dari jenis tujuannya.
      • Jika jenis sumber berukuran sama dengan jenis tujuan, maka nilai sumber diperlakukan sebagai nilai dari jenis tujuan
  • Untuk konversi dari decimal ke jenis integral, nilai sumber dibulatkan ke nol ke nilai integral terdekat, dan nilai integral ini menjadi hasil konversi. Jika nilai integral yang dihasilkan berada di luar rentang jenis tujuan, akan System.OverflowException dilemparkan.
  • Untuk konversi dari float atau double ke jenis integral, pemrosesan tergantung pada konteks pemeriksaan luapan (§12.8.20) tempat konversi berlangsung:
    • Dalam konteks yang dicentang, konversi berlanjut sebagai berikut:
      • Jika nilai operand adalah NaN atau tak terbatas, akan System.OverflowException dilemparkan.
      • Jika tidak, operand sumber dibulatkan menuju nol ke nilai integral terdekat. Jika nilai integral ini berada dalam rentang jenis tujuan, maka nilai ini adalah hasil konversi.
      • Jika tidak, dilemparkan System.OverflowException .
    • Dalam konteks yang tidak dicentang, konversi selalu berhasil, dan berlanjut sebagai berikut.
      • Jika nilai operand adalah NaN atau tak terbatas, hasil konversi adalah nilai yang tidak ditentukan dari jenis tujuan.
      • Jika tidak, operand sumber dibulatkan menuju nol ke nilai integral terdekat. Jika nilai integral ini berada dalam rentang jenis tujuan, maka nilai ini adalah hasil konversi.
      • Jika tidak, hasil konversi adalah nilai yang tidak ditentukan dari jenis tujuan.
  • Untuk konversi dari double ke float, nilai dibulatkan double ke nilai terdekat float . double Jika nilai terlalu kecil untuk diwakili sebagai float, hasilnya menjadi nol dengan tanda yang sama dengan nilai . Jika besarnya double nilai terlalu besar untuk diwakili sebagai float, hasilnya menjadi tak terbatas dengan tanda yang sama dengan nilai . Jika nilainya double adalah NaN, hasilnya juga NaN.
  • Untuk konversi dari atau ke , nilai sumber dikonversi ke float representasi dan dibulatkan ke angka terdekat jika diperlukan (double).decimaldecimal
    • Jika nilai sumber terlalu kecil untuk direpresentasikan sebagai decimal, hasilnya menjadi nol, mempertahankan tanda nilai asli jika decimal mendukung nilai nol yang ditandatangani.
    • Jika besarnya nilai sumber terlalu besar untuk direpresentasikan sebagai decimal, atau nilai tersebut tidak terbatas, hasilnya adalah infinity mempertahankan tanda nilai asli, jika representasi desimal mendukung tak terbatas; jika tidak, System.OverflowException akan dilemparkan.
    • Jika nilai sumber adalah NaN, hasilnya adalah NaN jika representasi desimal mendukung NaN; jika tidak, System.OverflowException dilemparkan.
  • Untuk konversi dari decimal ke float atau double, nilai dibulatkan decimal ke nilai terdekat double atau float . Jika besarnya nilai sumber terlalu besar untuk diwakili dalam jenis target, atau nilai tersebut tidak terbatas, hasilnya adalah infinity mempertahankan tanda nilai asli. Jika nilai sumber adalah NaN, hasilnya adalah NaN. Meskipun konversi ini mungkin kehilangan presisi, itu tidak pernah menyebabkan pengecualian dilemparkan.

Catatan: decimal Jenis ini tidak diperlukan untuk mendukung nilai infinities atau NaN tetapi dapat melakukannya; rentangnya mungkin lebih kecil dari rentang float dan double, tetapi tidak dijamin. Untuk decimal representasi tanpa nilai infinities atau NaN, dan dengan rentang yang lebih kecil dari float, hasil konversi dari decimal ke atau floatdouble tidak akan pernah tak terbatas atau NaN. catatan akhir

10.3.3 Konversi enumerasi eksplisit

Konversi enumerasi eksplisit adalah:

  • Dari sbyte, , byteshort, ushort, intuint, , long, ulong, char, float, double, , atau decimal ke enum_type apa pun.
  • Dari enum_type apa pun
  • Dari enum_type ke enum_type lainnya.

Konversi enumerasi eksplisit antara dua jenis diproses dengan memperlakukan enum_type yang berpartisipasi sebagai jenis yang mendasar dari enum_type tersebut, lalu melakukan konversi numerik implisit atau eksplisit antara jenis yang dihasilkan.

Contoh: Mengingat enum_typeE dengan jenis intyang mendasar , konversi dari E ke byte diproses sebagai konversi numerik eksplisit (§10,3,2) dari int ke byte, dan konversi dari byte ke E diproses sebagai konversi numerik implisit (§10,2,3) dari byte ke int. contoh akhir

10.3.4 Konversi nullable eksplisit

Konversi nullable eksplisit adalah konversi nullable (§10.6.1) yang berasal dari konversi eksplisit dan implisit yang telah ditentukan sebelumnya.

10.3.5 Konversi referensi eksplisit

Konversi referensi eksplisit adalah:

  • Dari objek ke reference_type lainnya.
  • Dari class_typehingga class_typeS, yang disediakan adalah kelas dasar .T
  • Dari class_type apa pun S
  • Dari interface_type apa pun S
  • Dari interface_typeShingga interface_type, yang disediakan T tidak berasal dari S.
  • dengan jenis S elemen ke Sᵢ dengan jenis Telemen , asalkan semua hal berikut ini benar:
    • S dan T hanya berbeda dalam jenis elemen. Dengan kata lain, S dan T memiliki jumlah dimensi yang sama.
    • Konversi referensi eksplisit ada dari Sᵢ ke Tᵢ.
  • Dari System.Array dan antarmuka yang diimplementasikannya, ke array_type apa pun.
  • Dari array_type S[]ada konversi identitas atau konversi referensi eksplisit dari System.Collections.Generic.IList<T> ke System.Collections.Generic.IReadOnlyList<T>.
  • Dari System.Collections.Generic.IList<S>, System.Collections.Generic.IReadOnlyList<S>, dan antarmuka dasarnya ke jenis T[]array dimensi tunggal , asalkan ada konversi identitas atau konversi referensi eksplisit dari S ke T.
  • Dari System.Delegate dan antarmuka yang diimplementasikannya ke delegate_type apa pun.
  • Dari jenis S referensi ke jenis T referensi jika memiliki konversi referensi eksplisit dari S ke jenis T₀ referensi dan T₀ dan ada konversi identitas dari T₀ ke T.
  • Dari jenis S referensi ke antarmuka atau jenis T delegasi jika ada konversi referensi eksplisit dari S ke antarmuka atau jenis T₀ delegasi dan dapat T₀ dikonversi varians ke T atau T dapat dikonversi varians ke T₀§18.2.3.3.
  • Dari D<S₁...Sᵥ> ke D<T₁...Tᵥ> tempat D<X₁...Xᵥ> adalah jenis delegasi generik, D<S₁...Sᵥ> tidak kompatibel dengan atau identik D<T₁...Tᵥ>dengan , dan untuk setiap parameter Xᵢ jenis penangguhan D berikut:
    • Jika Xᵢ invarian, maka Sᵢ identik dengan Tᵢ.
    • Jika Xᵢ kovarian, maka ada konversi identitas, konversi referensi implisit, atau konversi referensi eksplisit dari Sᵢ ke Tᵢ.
    • Jika Xᵢ kontravarian, maka Sᵢ dan Tᵢ merupakan jenis referensi yang identik atau keduanya.
  • Konversi eksplisit yang melibatkan parameter jenis yang diketahui sebagai jenis referensi. Untuk detail selengkapnya tentang konversi eksplisit yang melibatkan parameter jenis, lihat §10.3.8.

Konversi referensi eksplisit adalah konversi antara reference_typeyang memerlukan pemeriksaan run-time untuk memastikan konversi tersebut benar.

Agar konversi referensi eksplisit berhasil pada run-time, nilai operand sumber harus , atau jenis objek yang direferensikan nulloleh operand sumber adalah jenis yang dapat dikonversi ke jenis tujuan dengan konversi referensi implisit (§10.2.8). Jika konversi referensi eksplisit gagal, akan System.InvalidCastException dilemparkan.

Catatan: Konversi referensi, implisit atau eksplisit, tidak pernah mengubah nilai referensi itu sendiri (§8.2.1), hanya jenisnya; tidak mengubah jenis atau nilai objek yang dirujuk. catatan akhir

10.3.6 Konversi tuple eksplisit

Konversi eksplisit ada dari ekspresi E tuple ke jenis T tuple jika E memiliki aritas yang sama dengan T dan konversi implisit atau eksplisit ada dari setiap elemen ke E jenis elemen yang sesuai di T. Konversi dilakukan dengan membuat instans jenis Tyang System.ValueTuple<...> sesuai, dan menginisialisasi setiap bidangnya secara berurutan dari kiri ke kanan dengan mengevaluasi ekspresi elemen tuple yang sesuai dari E, mengonversinya ke jenis elemen yang sesuai menggunakan T konversi eksplisit yang ditemukan, dan menginisialisasi bidang dengan hasilnya.

10.3.7 Konversi unboxing

Konversi pembatalan kotak memungkinkan reference_type dikonversi secara eksplisit ke value_type. Konversi pembukaan kotak berikut ada:

  • Dari jenis object ke value_type apa pun.
  • Dari jenis System.ValueType ke value_type apa pun.
  • Dari jenis System.Enum ke enum_type apa pun.
  • Dari interface_type apa pun hingga non_nullable_value_type apa pun yang mengimplementasikan interface_type.
  • Dari interface_type apa pun Ike non_nullable_value_type di mana ada konversi pembukaan kotak dari interface_typeI₀ ke jenis non_nullable_value dan konversi identitas dari I ke I₀.
  • Dari interface_typeI apa pun ke non_nullable_value_type di mana ada konversi pembatalan pengemasan dari interface_typeI₀ ke non_nullable_value_type dan I₀ dapat dikonversi varians ke I atau I dapat dikonversi varians ke I₀ (§18.2.3.3).
  • Dari reference_type apa pun ke nullable_value_type mana pun di mana ada konversi pembukaan kotak dari reference_type ke non_nullable_value_type yang mendasar dari nullable_value_type.
  • Dari parameter jenis yang tidak diketahui sebagai jenis nilai ke jenis apa pun sehingga konversi diizinkan oleh §10.3.8.

Operasi pembukaan kotak ke non_nullable_value_type terdiri dari pemeriksaan pertama bahwa instans objek adalah nilai kotak dari non_nullable_value_type yang diberikan, lalu menyalin nilai dari instans.

Membuka kotak ke nullable_value_type menghasilkan nilai null nullable_value_type jika operand sumber adalah null, atau hasil yang dibungkus dari membuka kotak instans objek ke jenis nullable_value_type yang mendasar jika tidak.

Catatan: Mengacu pada kelas tinju imajiner yang dijelaskan dalam §10.2.9, konversi pembatalan kotak objek ke value_typeS terdiri dari menjalankan ekspresi ((S_Boxing)box).value. Dengan demikian, pernyataan

object box = new S();
S s = (S)box;

secara konseptual sesuai dengan

object box = new S_Boxing(new S());
S s = ((S_Boxing)box).value;

catatan akhir

Agar konversi pembukaan kotak ke non_nullable_value_type tertentu berhasil pada run-time, nilai operand sumber harus menjadi referensi ke nilai kotak dari non_nullable_value_type tersebut. Jika operand sumber adalah null dilemparkan System.NullReferenceException . Jika operand sumber adalah referensi ke objek yang tidak kompatibel, akan System.InvalidCastException dilemparkan.

Agar konversi pembukaan kotak ke nullable_value_type tertentu berhasil pada run-time, nilai operand sumber harus null atau referensi ke nilai kotak dari non_nullable_value_type yang mendasari nullable_value_type. Jika operand sumber adalah referensi ke objek yang tidak kompatibel, akan System.InvalidCastException dilemparkan.

10.3.8 Konversi eksplisit yang melibatkan parameter jenis

yang dikenal sebagai jenis referensi (T), konversi referensi eksplisit berikut (§10.3.5) ada:

  • Dari kelas C dasar yang efektif dari T ke T dan dari kelas dasar apa pun hingga CT .
  • Dari interface_type apa pun hingga T.
  • Dari T ke interface_typeyang disediakan belum ada konversi referensi implisit dari I ke T.
  • Dari type_parameterU yang T disediakan tergantung T pada U (§15.2.5).

    Catatan: Karena T dikenal sebagai jenis referensi, dalam cakupan T, jenis run-time Anda akan selalu menjadi jenis referensi, bahkan jika U tidak diketahui sebagai jenis referensi pada waktu kompilasi. catatan akhir

Untuk type_parameterT yang tidak diketahui sebagai jenis referensi (§15.2.5), konversi berikut yang melibatkan T dianggap sebagai konversi pembuka kotak (§10.3.7) pada waktu kompilasi. Pada run-time, jika T adalah jenis nilai, konversi dijalankan sebagai konversi unboxing. Pada run-time, jika T merupakan jenis referensi, konversi dijalankan sebagai konversi referensi eksplisit atau konversi identitas.

  • Dari kelas C dasar yang efektif dari T ke T dan dari kelas dasar apa pun hingga CT .

    Catatan: C akan menjadi salah satu jenis System.Object, , System.ValueTypeatau System.Enum (jika tidak T , akan diketahui sebagai jenis referensi). catatan akhir

  • Dari interface_type apa pun hingga T.

yang T diketahui sebagai jenis referensi (§15.2.5), konversi eksplisit berikut ada:

  • Dari T ke interface_typebelum ada konversi implisit dari I ke T. Konversi ini terdiri dari konversi tinju implisit (§10.2.9) dari T ke object diikuti dengan konversi referensi eksplisit dari object ke I. Pada run-time, jika T adalah jenis nilai, konversi dijalankan sebagai konversi tinju diikuti dengan konversi referensi eksplisit. Pada run-time, jika T merupakan jenis referensi, konversi dijalankan sebagai konversi referensi eksplisit.
  • Dari parameter U jenis hingga T yang disediakan tergantung T pada U (§15.2.5). Pada run-time, jika T adalah jenis nilai dan U merupakan jenis referensi, konversi dijalankan sebagai konversi unboxing. Pada run-time, jika dan TU merupakan jenis nilai, maka T dan U harus jenis yang sama dan tidak ada konversi yang dilakukan. Pada run-time, jika T merupakan jenis referensi, maka U tentu juga merupakan jenis referensi dan konversi dijalankan sebagai konversi referensi eksplisit atau konversi identitas.

Dalam semua kasus, aturan memastikan bahwa konversi dijalankan sebagai konversi unboxing jika dan hanya jika pada run-time konversi berasal dari jenis referensi ke jenis nilai.

Aturan di atas tidak mengizinkan konversi eksplisit langsung dari parameter jenis yang tidak dibatasi ke jenis non-antarmuka, yang mungkin mengejutkan. Alasan untuk aturan ini adalah untuk mencegah kebingungan dan membuat semantik konversi tersebut jelas.

Contoh: Pertimbangkan deklarasi berikut:

class X<T>
{
    public static long F(T t)
    {
        return (long)t;         // Error
    }
}

Jika konversi eksplisit langsung dari t ke long diizinkan, seseorang mungkin dengan mudah mengharapkan itu X<int>.F(7) akan mengembalikan 7L. Namun, itu tidak akan, karena konversi numerik standar hanya dipertimbangkan ketika jenis diketahui numerik pada waktu pengikatan. Untuk memperjelas semantik, contoh di atas harus ditulis:

class X<T>
{
    public static long F(T t)
    {
        return (long)(object)t;         // Ok, but will only work when T is long
    }
}

Kode ini sekarang akan dikompilasi tetapi mengeksekusi X<int>.F(7) kemudian akan melemparkan pengecualian pada run-time, karena kotak tidak dapat dikonversi int langsung ke long.

contoh akhir

10.3.9 Konversi eksplisit yang ditentukan pengguna

Konversi eksplisit yang ditentukan pengguna terdiri dari konversi eksplisit standar opsional, diikuti dengan eksekusi operator konversi implisit atau eksplisit yang ditentukan pengguna, diikuti oleh konversi eksplisit standar opsional lainnya. Aturan yang tepat untuk mengevaluasi konversi eksplisit yang ditentukan pengguna dijelaskan dalam §10.5.5.

10.4 Konversi standar

10.4.1 Umum

Konversi standar adalah konversi yang telah ditentukan sebelumnya yang dapat terjadi sebagai bagian dari konversi yang ditentukan pengguna.

10.4.2 Konversi implisit Standar

Konversi implisit berikut diklasifikasikan sebagai konversi implisit standar:

Konversi implisit standar secara khusus mengecualikan konversi implisit yang ditentukan pengguna.

10.4.3 Konversi eksplisit Standar

Konversi eksplisit standar adalah semua konversi implisit standar ditambah subset konversi eksplisit di mana konversi implisit standar yang berlawanan ada.

Catatan: Dengan kata lain, jika konversi implisit standar ada dari jenis A ke jenis B, maka konversi eksplisit standar ada dari jenis A ke jenis B dan dari jenis ke jenis BA. catatan akhir

10.5 Konversi yang ditentukan pengguna

10.5.1 Umum

C# memungkinkan konversi implisit dan eksplisit yang telah ditentukan sebelumnya untuk ditambah oleh konversi yang ditentukan pengguna. Konversi yang ditentukan pengguna diperkenalkan dengan mendeklarasikan operator konversi (§15.10.4) di kelas dan jenis struktur.

10.5.2 Konversi yang ditentukan pengguna yang diizinkan

C# hanya mengizinkan konversi tertentu yang ditentukan pengguna untuk dideklarasikan. Secara khusus, tidak mungkin untuk menentukan ulang konversi implisit atau eksplisit yang sudah ada.

Untuk jenis S sumber dan jenis Ttarget tertentu , jika S atau T jenis nilai nullable, biarkan S₀ dan T₀ lihat jenis yang mendasarnya, jika tidak S₀ dan T₀ sama dengan S dan T masing-masing. Kelas atau struktur diizinkan untuk mendeklarasikan konversi dari jenis sumber ke jenis ST target hanya jika semua hal berikut ini benar:

  • S₀ dan T₀ merupakan jenis yang berbeda.
  • Baik S₀ atau T₀ adalah kelas atau jenis struct tempat deklarasi operator berlangsung.
  • Tidak S₀ juga T₀bukan interface_type.
  • Tidak termasuk konversi yang ditentukan pengguna, konversi tidak ada dari S ke T atau dari T ke S.

Pembatasan yang berlaku untuk konversi yang ditentukan pengguna ditentukan dalam §15.10.4.

10.5.3 Evaluasi konversi yang ditentukan pengguna

Konversi yang ditentukan pengguna mengonversi ekspresi sumber, yang mungkin memiliki jenis sumber, ke jenis lain, yang disebut jenis target. Evaluasi pusat konversi yang ditentukan pengguna pada menemukan operator konversi yang ditentukan pengguna yang paling spesifik untuk ekspresi sumber dan jenis target. Penentuan ini dipecah menjadi beberapa langkah:

  • Menemukan set kelas dan struktur tempat operator konversi yang ditentukan pengguna akan dipertimbangkan. Set ini terdiri dari jenis sumber dan kelas dasarnya, jika jenis sumber ada, bersama dengan jenis target dan kelas dasarnya. Untuk tujuan ini diasumsikan bahwa hanya kelas dan struktur yang dapat mendeklarasikan operator yang ditentukan pengguna, dan bahwa jenis non-kelas tidak memiliki kelas dasar. Selain itu, jika jenis sumber atau target adalah jenis nilai nullable, jenis yang mendasarnya digunakan sebagai gantinya.
  • Dari kumpulan jenis tersebut, menentukan operator konversi yang ditentukan pengguna dan diangkat mana yang berlaku. Agar operator konversi berlaku, dimungkinkan untuk melakukan konversi standar (§10,4) dari ekspresi sumber ke jenis operand operator, dan dimungkinkan untuk melakukan konversi standar dari jenis hasil operator ke jenis target.
  • Dari set operator yang ditentukan pengguna yang berlaku, menentukan operator mana yang tidak ambigu yang paling spesifik. Secara umum, operator yang paling spesifik adalah operator yang jenis operand-nya "paling dekat" dengan ekspresi sumber dan yang jenis hasilnya "paling dekat" dengan jenis target. Operator konversi yang ditentukan pengguna lebih disukai daripada operator konversi yang diangkat. Aturan yang tepat untuk menetapkan operator konversi yang ditentukan pengguna yang paling spesifik ditentukan ditentukan dalam subklaus berikut.

Setelah operator konversi yang ditentukan pengguna yang paling spesifik diidentifikasi, eksekusi aktual konversi yang ditentukan pengguna melibatkan hingga tiga langkah:

  • Pertama, jika diperlukan, lakukan konversi standar dari ekspresi sumber ke jenis operand operator konversi yang ditentukan pengguna atau diangkat.
  • Selanjutnya, panggil operator konversi yang ditentukan pengguna atau diangkat untuk melakukan konversi.
  • Terakhir, jika diperlukan, melakukan konversi standar dari jenis hasil operator konversi yang ditentukan pengguna ke jenis target.

Evaluasi konversi yang ditentukan pengguna tidak pernah melibatkan lebih dari satu operator konversi yang ditentukan pengguna atau diangkat. Dengan kata lain, konversi dari jenis ke jenis ST tidak akan pernah terlebih dahulu menjalankan konversi yang ditentukan pengguna dari S ke X lalu menjalankan konversi yang ditentukan pengguna dari X ke T.

  • Definisi yang tepat tentang evaluasi konversi implisit atau eksplisit yang ditentukan pengguna diberikan dalam subklaus berikut. Definisi menggunakan istilah-istilah berikut:
  • Jika konversi implisit standar (§10.4.2) ada dari jenis A ke jenis B, dan jika baik A maupun B bukan interface_type, maka A dianggap termasuk dalamB, dan B dianggap mencakupA.
  • Jika konversi implisit standar (§10,4,2) ada dari ekspresi E ke jenis B, dan jika tidak B atau jenis E (jika memilikinya) interface_type, kemudian E dikatakan dilirik olehB, dan B dikatakan kepada mencakupE.
  • Jenis yang paling mencakup dalam sekumpulan jenis adalah satu jenis yang mencakup semua jenis lain dalam set. Jika tidak ada jenis tunggal yang mencakup semua jenis lainnya, maka set tidak memiliki jenis yang paling mencakup. Dalam istilah yang lebih intuitif, jenis yang paling mencakup adalah jenis "terbesar" dalam set —satu jenis yang masing-masing jenisnya dapat dikonversi secara implisit.
  • Jenis yang paling mencakup dalam sekumpulan jenis adalah satu jenis yang disertakan oleh semua jenis lain dalam set. Jika tidak ada jenis tunggal yang dililit oleh semua jenis lainnya, maka set tidak memiliki jenis yang paling dilirik. Dalam istilah yang lebih intuitif, jenis yang paling mencakup adalah jenis "terkecil" dalam set —satu jenis yang dapat dikonversi secara implisit ke masing-masing jenis lainnya.

10.5.4 Konversi implisit yang ditentukan pengguna

Konversi implisit yang ditentukan pengguna dari ekspresi E ke jenis T diproses sebagai berikut:

  • Tentukan jenis S, S₀ dan T₀.

    • Jika E memiliki jenis, biarkan S jenis tersebut.
    • Jika S atau T adalah jenis nilai nullable, biarkan Sᵢ dan Tᵢ menjadi jenis yang mendasarnya, jika tidak, biarkan Sᵢ dan TᵢST, masing-masing.
    • Jika Sᵢ atau Tᵢ merupakan parameter jenis, biarkan S₀ dan T₀ jadilah kelas dasar yang efektif, jika tidak, biarkan S₀ dan T₀SₓTᵢ, masing-masing.
  • Temukan sekumpulan jenis, D, tempat operator konversi yang ditentukan pengguna akan dipertimbangkan. Set ini terdiri dari S₀ (jika S₀ ada dan merupakan kelas atau struktur), kelas S₀ dasar (jika S₀ ada dan merupakan kelas), dan T₀ (jika T₀ adalah kelas atau struktur). Jenis ditambahkan ke set D hanya jika konversi identitas ke jenis lain yang sudah disertakan dalam set tidak ada.

  • Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku, U. Set ini terdiri dari operator konversi implisit yang ditentukan pengguna dan diangkat yang dideklarasikan oleh kelas atau struktur dalam D konversi tersebut dari jenis yang mencakup E ke jenis yang dicakup oleh T. Jika U kosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.

    • Jika S ada dan salah satu operator dalam U konversi dari S, maka Sₓ adalah S.
    • Jika tidak, Sₓ adalah jenis yang paling mencakup dalam kumpulan gabungan jenis sumber operator di U. Jika tepat satu jenis yang paling lengkap tidak dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
  • Temukan jenis target yang paling spesifik, Tₓ, dari operator di U:

    • Jika salah satu operator dalam U konversi ke T, maka Tₓ adalah T.
    • Jika tidak, Tₓ adalah jenis yang paling mencakup dalam kumpulan gabungan jenis target operator di U. Jika tepat satu jenis yang paling mencakup tidak dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
  • Temukan operator konversi yang paling spesifik:

    • Jika U berisi tepat satu operator konversi yang ditentukan pengguna yang dikonversi dari Sₓ ke Tₓ, maka ini adalah operator konversi yang paling spesifik.
    • Jika tidak, jika U berisi tepat satu operator konversi yang diangkat yang dikonversi dari Sₓ ke Tₓ, maka ini adalah operator konversi yang paling spesifik.
    • Jika tidak, konversi bersifat ambigu dan terjadi kesalahan waktu kompilasi.
  • Terakhir, terapkan konversi:

    • Jika E belum memiliki jenis Sₓ, maka konversi implisit standar dari E ke Sₓ dilakukan.
    • Operator konversi yang paling spesifik dipanggil untuk mengonversi dari Sₓ ke Tₓ.
    • Jika Tₓ tidak T, maka konversi implisit standar dari Tₓ ke T dilakukan.

Konversi implisit yang ditentukan pengguna dari jenis S ke jenis T ada jika konversi implisit yang ditentukan pengguna ada dari variabel jenis S ke T.

10.5.5 Konversi eksplisit yang ditentukan pengguna

Konversi eksplisit yang ditentukan pengguna dari ekspresi E ke jenis T diproses sebagai berikut:

  • Tentukan jenis S, S₀ dan T₀.
    • Jika E memiliki jenis, biarkan S jenis tersebut.
    • Jika S atau T adalah jenis nilai nullable, biarkan Sᵢ dan Tᵢ menjadi jenis yang mendasarnya, jika tidak, biarkan Sᵢ dan TᵢST, masing-masing.
    • Jika Sᵢ atau Tᵢ merupakan parameter jenis, biarkan S₀ dan T₀ jadilah kelas dasar yang efektif, jika tidak, biarkan S₀ dan T₀SᵢTᵢ, masing-masing.
  • Temukan sekumpulan jenis, D, tempat operator konversi yang ditentukan pengguna akan dipertimbangkan. Set ini terdiri dari S₀ (jika S₀ ada dan merupakan kelas atau struktur), kelas S₀ dasar (jika S₀ ada dan merupakan kelas), T₀ (jika T₀ adalah kelas atau struct), dan kelas T₀ dasar (jika T₀ adalah kelas). Jenis ditambahkan ke set D hanya jika konversi identitas ke jenis lain yang sudah disertakan dalam set tidak ada.
  • Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku, U. Set ini terdiri dari operator konversi implisit atau eksplisit yang ditentukan pengguna dan diangkat yang dideklarasikan oleh kelas atau struktur dalam D konversi tersebut dari jenis yang mencakup E atau dicakup oleh S (jika ada) ke jenis yang mencakup atau dicakup oleh T. Jika U kosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
  • Temukan jenis sumber yang paling spesifik, Sₓ, dari operator di U:
    • Jika S ada dan salah satu operator dalam U konversi dari S, maka Sₓ adalah S.
    • Jika tidak, jika salah satu operator dalam U konversi dari jenis yang mencakup E, maka Sₓ adalah jenis yang paling terpusat dalam kumpulan gabungan jenis sumber operator tersebut. Jika tidak ada jenis yang paling lengkap yang dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
    • Jika tidak, Sₓ adalah jenis yang paling mencakup dalam kumpulan gabungan jenis sumber operator di U. Jika tepat satu jenis yang paling mencakup tidak dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
  • Temukan jenis target yang paling spesifik, Tₓ, dari operator di U:
    • Jika salah satu operator dalam U konversi ke T, maka Tₓ adalah T.
    • Jika tidak, jika salah satu operator dalam U konversi ke jenis yang disertakan oleh T, maka Tₓ adalah jenis yang paling mencakup dalam kumpulan gabungan jenis target operator tersebut. Jika tepat satu jenis yang paling mencakup tidak dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
    • Jika tidak, Tₓ adalah jenis yang paling mencakup dalam kumpulan gabungan jenis target operator di U. Jika tidak ada jenis yang paling lengkap yang dapat ditemukan, maka konversi ambigu dan terjadi kesalahan waktu kompilasi.
  • Temukan operator konversi yang paling spesifik:
    • Jika U berisi tepat satu operator konversi yang ditentukan pengguna yang dikonversi dari Sₓ ke Tₓ, maka ini adalah operator konversi yang paling spesifik.
    • Jika tidak, jika U berisi tepat satu operator konversi yang diangkat yang dikonversi dari Sₓ ke Tₓ, maka ini adalah operator konversi yang paling spesifik.
    • Jika tidak, konversi bersifat ambigu dan terjadi kesalahan waktu kompilasi.
  • Terakhir, terapkan konversi:
    • Jika E belum memiliki jenis Sₓ, maka konversi eksplisit standar dari E ke Sₓ dilakukan.
    • Operator konversi yang ditentukan pengguna yang paling spesifik dipanggil untuk mengonversi dari Sₓ ke Tₓ.
    • Jika Tₓ tidak T, maka konversi eksplisit standar dari Tₓ ke T dilakukan.

Konversi eksplisit yang ditentukan pengguna dari jenis S ke jenis T ada jika konversi eksplisit yang ditentukan pengguna ada dari variabel jenis S ke T.

10.6 Konversi yang melibatkan jenis nullable

10.6.1 Konversi Nullable

Konversi nullable mengizinkan konversi yang telah ditentukan sebelumnya yang beroperasi pada jenis nilai yang tidak dapat diubah ke null untuk juga digunakan dengan bentuk nullable dari jenis tersebut. Untuk setiap konversi implisit atau eksplisit yang telah ditentukan sebelumnya yang mengonversi dari jenis nilai yang tidak dapat diubah ke jenis STnilai yang tidak dapat diubah ke null (§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 dan §10.3.3), konversi nullable berikut ada:

  • Konversi implisit atau eksplisit dari S? ke T?
  • Konversi implisit atau eksplisit dari S ke T?
  • Konversi eksplisit dari S? ke T.

Konversi nullable itu sendiri diklasifikasikan sebagai konversi implisit atau eksplisit.

Konversi nullable tertentu diklasifikasikan sebagai konversi standar dan dapat terjadi sebagai bagian dari konversi yang ditentukan pengguna. Secara khusus, semua konversi nullable implisit diklasifikasikan sebagai konversi implisit standar (§10.4.2), dan konversi eksplisit nullable yang memenuhi persyaratan §10.4.3 diklasifikasikan sebagai konversi eksplisit standar.

Evaluasi konversi nullable berdasarkan konversi yang mendasar dari S ke T melanjutkan sebagai berikut:

  • Jika konversi nullable adalah dari S? ke T?:
    • Jika nilai sumber null (HasValue properti adalah false), hasilnya adalah nilai null dari jenis T?.
    • Jika tidak, konversi dievaluasi sebagai pembungkusan dari S? ke S, diikuti oleh konversi yang mendasar dari S ke T, diikuti dengan pembungkusan dari T ke T?.
  • Jika konversi nullable adalah dari S ke T?, konversi dievaluasi sebagai konversi yang mendasar dari S menjadi T diikuti dengan pembungkusan dari T ke T?.
  • Jika konversi nullable adalah dari S? ke T, konversi dievaluasi sebagai unwrapping dari S? ke S diikuti dengan konversi yang mendasar dari S ke T.

10.6.2 Konversi yang diangkat

Mengingat operator konversi yang ditentukan pengguna yang mengonversi dari jenis nilai yang tidak dapat diubah ke jenis S nilai yang tidak dapat diubah ke null, T konversi yang diangkat ada yang mengonversi dari ke S?.T? Operator konversi yang diangkat ini melakukan pembungkusan dari S? ke S diikuti oleh konversi yang ditentukan pengguna dari S ke T diikuti dengan pembungkusan dari T ke T?, kecuali bahwa nilai S? null dikonversi langsung ke nilai T?null . Operator konversi yang diangkat memiliki klasifikasi implisit atau eksplisit yang sama dengan operator konversi yang mendasar yang ditentukan pengguna.

10.7 Konversi fungsi anonim

10.7.1 Umum

anonymous_method_expression atau lambda_expression diklasifikasikan sebagai fungsi anonim (§12.19). Ekspresi tidak memiliki jenis, tetapi dapat dikonversi secara implisit ke jenis delegasi yang kompatibel. Beberapa ekspresi lambda juga dapat dikonversi secara implisit ke jenis pohon ekspresi yang kompatibel.

Secara khusus, fungsi F anonim kompatibel dengan jenis D delegasi yang disediakan:

  • Jika F berisi anonymous_function_signature, maka D dan F memiliki jumlah parameter yang sama.
  • Jika F tidak berisi anonymous_function_signature, maka D mungkin memiliki parameter nol atau lebih dari jenis apa pun, selama tidak ada parameter D yang merupakan parameter output.
  • Jika F memiliki daftar parameter yang ditik secara eksplisit, setiap parameter di D memiliki pengubah yang sama dengan parameter yang sesuai di dan konversi identitas ada di F antara parameter yang sesuai di F.
  • Jika F memiliki daftar parameter yang ditik secara implisit, D tidak memiliki parameter referensi atau output.
  • Jika isi F adalah ekspresi , danD memiliki jenis pengembalian yang batal atauF asinkron dan D memiliki «TaskType» jenis pengembalian (§15.14.1), maka ketika setiap parameter F diberikan jenis parameter yang sesuai di D, isinya F adalah ekspresi yang valid (w.r.t §12) yang akan diizinkan sebagai statement_expression (§13.7).
  • Jika isi F adalah blok, dan D memiliki jenis pengembalian yang batal atauF asinkron dan D memiliki «TaskType» jenis pengembalian , maka ketika setiap parameter F diberikan jenis parameter yang sesuai di D, isinya F adalah blok yang valid (w.r.t §13.3) di mana tidak ada return pernyataan yang menentukan ekspresi.
  • Jika isi F adalah ekspresi, dan baikF tidak asinkron dan D memiliki jenis pengembalian non-voidT, atauF asinkron dan D memiliki jenis pengembalian «TaskType»<T> (§15.14.1), maka ketika setiap parameter F diberi tipe yang sesuai dengan parameter di D, isi F adalah ekspresi yang valid (w.r.t §12) yang secara implisit dapat dikonversi ke T.
  • Jika isi F adalah blok, dan tidakF asinkron dan D memiliki jenis Tpengembalian non-void , asinkron dan F memiliki D jenis pengembalian, maka ketika setiap parameter «TaskType»<T> diberikan jenis parameter yang sesuai di F, isinya D adalah blok pernyataan yang valid (w.r.t F) dengan titik akhir yang tidak dapat dijangkau di mana setiap pernyataan pengembalian menentukan ekspresi yang secara implisit dapat dikonversi ke .

Contoh: Contoh berikut mengilustrasikan aturan ini:

delegate void D(int x);
D d1 = delegate { };                         // Ok
D d2 = delegate() { };                       // Error, signature mismatch
D d3 = delegate(long x) { };                 // Error, signature mismatch
D d4 = delegate(int x) { };                  // Ok
D d5 = delegate(int x) { return; };          // Ok
D d6 = delegate(int x) { return x; };        // Error, return type mismatch

delegate void E(out int x);
E e1 = delegate { };                         // Error, E has an output parameter
E e2 = delegate(out int x) { x = 1; };       // Ok
E e3 = delegate(ref int x) { x = 1; };       // Error, signature mismatch

delegate int P(params int[] a);
P p1 = delegate { };                         // Error, end of block reachable
P p2 = delegate { return; };                 // Error, return type mismatch
P p3 = delegate { return 1; };               // Ok
P p4 = delegate { return "Hello"; };         // Error, return type mismatch
P p5 = delegate(int[] a)                     // Ok
{
    return a[0];
};
P p6 = delegate(params int[] a)              // Error, params modifier
{
    return a[0];
};
P p7 = delegate(int[] a)                     // Error, return type mismatch
{
    if (a.Length > 0) return a[0];
    return "Hello";
};

delegate object Q(params int[] a);
Q q1 = delegate(int[] a)                    // Ok
{
    if (a.Length > 0) return a[0];
    return "Hello";
};

contoh akhir

Contoh: Contoh berikut menggunakan jenis Func<A,R> delegasi generik yang mewakili fungsi yang mengambil argumen jenis A dan mengembalikan nilai jenis R:

delegate R Func<A,R>(A arg);

Dalam penugasan

Func<int,int> f1 = x => x + 1; // Ok
Func<int,double> f2 = x => x + 1; // Ok
Func<double,int> f3 = x => x + 1; // Error
Func<int, Task<int>> f4 = async x => x + 1; // Ok

parameter dan jenis pengembalian dari setiap fungsi anonim ditentukan dari jenis variabel tempat fungsi anonim ditetapkan.

Penugasan pertama berhasil mengonversi fungsi anonim ke jenis Func<int,int> delegasi karena, ketika x diberikan jenis int, x + 1 adalah ekspresi valid yang secara implisit dapat dikonversi ke jenis int.

Demikian juga, penetapan kedua berhasil mengonversi fungsi anonim ke jenis delegasi Func<int, ganda> karena hasil x + 1 (dari jenis int) secara implisit dapat dikonversi ke jenis double.

Namun, penugasan ketiga adalah kesalahan waktu kompilasi karena, ketika x diberikan jenis double, hasil x + 1 (dari jenis double) tidak secara implisit dapat dikonversi ke jenis int.

Penugasan keempat berhasil mengonversi fungsi asinkron anonim ke jenis Func<int, Task<int>> delegasi karena hasil x + 1 (dari jenis int) secara implisit dapat dikonversi ke jenis int pengembalian efektif dari asinkron lambda, yang memiliki jenis Task<int>pengembalian .

contoh akhir

Ekspresi F lambda kompatibel dengan jenis Expression<D> pohon ekspresi jika F kompatibel dengan jenis Ddelegasi . Ini tidak berlaku untuk metode anonim, hanya ekspresi lambda.

Fungsi anonim dapat memengaruhi resolusi kelebihan beban, dan berpartisipasi dalam inferensi jenis. Lihat §12.6 untuk detail lebih lanjut.

10.7.2 Evaluasi konversi fungsi anonim ke jenis delegasi

Konversi fungsi anonim ke jenis delegasi menghasilkan instans delegasi yang mereferensikan fungsi anonim dan set (mungkin kosong) dari variabel luar yang ditangkap yang aktif pada saat evaluasi. Ketika delegasi dipanggil, isi fungsi anonim dijalankan. Kode dalam isi dijalankan menggunakan sekumpulan variabel luar yang ditangkap yang direferensikan oleh delegasi. delegate_creation_expression (§12.8.17.5) dapat digunakan sebagai sintaks alternatif untuk mengonversi metode anonim ke jenis delegasi.

Daftar pemanggilan delegasi yang dihasilkan dari fungsi anonim berisi satu entri. Objek target yang tepat dan metode target delegasi tidak ditentukan. Secara khusus, tidak ditentukan apakah objek target delegasi adalah null, this nilai anggota fungsi penutup, atau beberapa objek lainnya.

Konversi fungsi anonim yang identik secara semantik dengan kumpulan instans variabel luar yang ditangkap (mungkin kosong) yang sama ke jenis delegasi yang sama diizinkan (tetapi tidak diperlukan) untuk mengembalikan instans delegasi yang sama. Istilah yang identik secara semantik digunakan di sini untuk berarti bahwa eksekusi fungsi anonim akan, dalam semua kasus, menghasilkan efek yang sama mengingat argumen yang sama. Aturan ini mengizinkan kode seperti berikut ini untuk dioptimalkan.

delegate double Function(double x);

class Test
{
    static double[] Apply(double[] a, Function f)
    {
        double[] result = new double[a.Length];
        for (int i = 0; i < a.Length; i++)
        {
            result[i] = f(a[i]);
        }
        return result;
    }

    static void F(double[] a, double[] b)
    {
        a = Apply(a, (double x) => Math.Sin(x));
        b = Apply(b, (double y) => Math.Sin(y));
        ...
    }
}

Karena dua delegasi fungsi anonim memiliki kumpulan variabel luar yang ditangkap (kosong) yang sama, dan karena fungsi anonim secara semantik identik, kompilator diizinkan untuk meminta delegasi merujuk ke metode target yang sama. Kompilator diizinkan untuk mengembalikan instans delegasi yang sama persis dari kedua ekspresi fungsi anonim.

10.7.3 Evaluasi konversi ekspresi lambda ke jenis pohon ekspresi

Konversi ekspresi lambda ke jenis pohon ekspresi menghasilkan pohon ekspresi (§8,6). Lebih tepatnya, evaluasi konversi ekspresi lambda menghasilkan struktur objek yang mewakili struktur ekspresi lambda itu sendiri.

Tidak setiap ekspresi lambda dapat dikonversi ke jenis pohon ekspresi. Konversi ke jenis delegasi yang kompatibel selalu ada, tetapi mungkin gagal pada waktu kompilasi karena alasan yang ditentukan implementasi.

Catatan: Alasan umum untuk ekspresi lambda gagal dikonversi ke jenis pohon ekspresi meliputi:

  • Ini memiliki badan blok
  • Ini memiliki pengubah async
  • Ini berisi operator penugasan
  • Ini berisi parameter output atau referensi
  • Ini berisi ekspresi yang terikat secara dinamis

catatan akhir

10.8 Konversi grup metode

Konversi implisit ada dari grup metode (§12,2) ke jenis delegasi yang kompatibel (§20,4). Jika D adalah jenis delegasi, dan E merupakan ekspresi yang diklasifikasikan sebagai grup metode, maka D kompatibel dengan E jika dan hanya jika E berisi setidaknya satu metode yang berlaku dalam bentuk normalnya (§12.6.4.2) ke daftar argumen apa pun (§12.6.2) memiliki jenis dan pengubah yang cocok dengan jenis parameter dan pengubah D, seperti yang dijelaskan dalam hal berikut.

Aplikasi waktu kompilasi konversi dari grup E metode ke jenis D delegasi dijelaskan dalam hal berikut.

  • Metode tunggal M dipilih sesuai dengan pemanggilan metode (§12.8.10.2) formulir E(A), dengan modifikasi berikut:
    • Daftar A argumen adalah daftar ekspresi, masing-masing diklasifikasikan sebagai variabel dan dengan jenis dan pengubah (in, out, atau ref) dari parameter yang sesuai dalam — kecuali parameter jenis D, di mana ekspresi yang sesuai memiliki jenis dynamic alih-alih object.
    • Metode kandidat yang dipertimbangkan hanya metode yang berlaku dalam bentuk normalnya dan tidak menghilangkan parameter opsional apa pun (§12.6.4.2). Dengan demikian, metode kandidat diabaikan jika hanya berlaku dalam bentuk yang diperluas, atau jika satu atau beberapa parameter opsional mereka tidak memiliki parameter yang sesuai di D.
  • Konversi dianggap ada jika algoritma §12.8.10.2
  • Jika metode M yang dipilih adalah metode instans, ekspresi instans yang terkait dengan E menentukan objek target delegasi.
  • Jika metode M yang dipilih adalah metode ekstensi yang ditandai dengan akses anggota pada ekspresi instans, ekspresi instans tersebut menentukan objek target delegasi.
  • Hasil konversi adalah nilai jenis D, yaitu delegasi yang mengacu pada metode yang dipilih dan objek target.

Contoh: Berikut ini menunjukkan konversi grup metode:

delegate string D1(object o);
delegate object D2(string s);
delegate object D3();
delegate string D4(object o, params object[] a);
delegate string D5(int i);
class Test
{
    static string F(object o) {...}

    static void G()
    {
        D1 d1 = F;         // Ok
        D2 d2 = F;         // Ok
        D3 d3 = F;         // Error – not applicable
        D4 d4 = F;         // Error – not applicable in normal form
        D5 d5 = F;         // Error – applicable but not compatible
    }
}

Penugasan untuk d1 secara implisit mengonversi grup F metode menjadi nilai jenis D1.

Penugasan untuk d2 menunjukkan bagaimana mungkin untuk membuat delegasi ke metode yang memiliki jenis parameter yang kurang diturunkan (kontravarian) dan jenis pengembalian yang lebih turunan (kovarian).

Penugasan untuk d3 menunjukkan bagaimana tidak ada konversi jika metode tidak berlaku.

Penugasan untuk d4 menunjukkan bagaimana metode harus berlaku dalam bentuk normalnya.

Penugasan untuk d5 menunjukkan bagaimana parameter dan jenis pengembalian delegasi dan metode diizinkan untuk berbeda hanya untuk jenis referensi.

contoh akhir

Seperti halnya semua konversi implisit dan eksplisit lainnya, operator cast dapat digunakan untuk melakukan konversi tertentu secara eksplisit.

Contoh: Dengan demikian, contoh

object obj = new EventHandler(myDialog.OkClick);

dapat ditulis sebagai gantinya

object obj = (EventHandler)myDialog.OkClick;

contoh akhir

Konversi grup metode dapat merujuk ke metode generik, baik dengan secara eksplisit menentukan argumen jenis dalam E, atau melalui inferensi jenis (§12.6.3). Jika inferensi jenis digunakan, jenis parameter delegasi digunakan sebagai jenis argumen dalam proses inferensi. Jenis pengembalian delegasi tidak digunakan untuk inferensi. Apakah argumen jenis ditentukan atau disimpulkan, argumen tersebut adalah bagian dari proses konversi grup metode; ini adalah argumen jenis yang digunakan untuk memanggil metode target ketika delegasi yang dihasilkan dipanggil.

Contoh:

delegate int D(string s, int i);
delegate int E();

class X
{
    public static T F<T>(string s, T t) {...}
    public static T G<T>() {...}

    static void Main()
    {
        D d1 = F<int>;        // Ok, type argument given explicitly
        D d2 = F;             // Ok, int inferred as type argument
        E e1 = G<int>;        // Ok, type argument given explicitly
        E e2 = G;             // Error, cannot infer from return type
    }
}

contoh akhir

Grup metode dapat memengaruhi resolusi kelebihan beban, dan berpartisipasi dalam inferensi jenis. Lihat §12.6 untuk detail lebih lanjut.

Evaluasi run-time dari konversi grup metode berlanjut sebagai berikut:

  • Jika metode yang dipilih pada waktu kompilasi adalah metode instans, atau merupakan metode ekstensi yang diakses sebagai metode instans, objek target delegasi ditentukan dari ekspresi instans yang terkait dengan E:
    • Ekspresi instans dievaluasi. Jika evaluasi ini menyebabkan pengecualian, tidak ada langkah lebih lanjut yang dijalankan.
    • Jika ekspresi instans adalah reference_type, nilai yang dihitung oleh ekspresi instans menjadi objek target. Jika metode yang dipilih adalah metode instans dan objek target adalah null, System.NullReferenceException akan dilemparkan dan tidak ada langkah lebih lanjut yang dijalankan.
    • Jika ekspresi instans adalah value_type, operasi tinju (§10.2.9) dilakukan untuk mengonversi nilai menjadi objek, dan objek ini menjadi objek target.
  • Jika tidak, metode yang dipilih adalah bagian dari panggilan metode statis, dan objek target delegasi adalah null.
  • Instans delegasi jenis D delegasi diperoleh dengan referensi ke metode yang ditentukan pada waktu kompilasi dan referensi ke objek target yang dihitung di atas, sebagai berikut:
    • Konversi diizinkan (tetapi tidak diperlukan) untuk menggunakan instans delegasi yang ada yang sudah berisi referensi ini.
    • Jika instans yang ada tidak digunakan kembali, instans baru dibuat (§20,5). Jika tidak ada cukup memori yang tersedia untuk mengalokasikan instans baru, akan System.OutOfMemoryException dilemparkan. Jika tidak, instans diinisialisasi dengan referensi yang diberikan.