Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam definisi umum, gunakan where klausul untuk menentukan batasan pada jenis yang Anda gunakan sebagai argumen untuk parameter jenis dalam jenis generik, metode, delegasi, atau fungsi lokal. Anda dapat menentukan antarmuka, kelas dasar, atau mengharuskan jenis generik menjadi referensi, nilai, atau jenis yang tidak dikelola. Batasan ini menyatakan kemampuan yang harus dimiliki argumen jenis. Tempatkan where klausul setelah kelas dasar yang dideklarasikan atau antarmuka yang diimplementasikan.
Referensi bahasa C# mendokumentasikan versi bahasa C# yang paling baru dirilis. Ini juga berisi dokumentasi awal untuk fitur dalam pratinjau publik untuk rilis bahasa yang akan datang.
Dokumentasi mengidentifikasi fitur apa pun yang pertama kali diperkenalkan dalam tiga versi terakhir bahasa atau dalam pratinjau publik saat ini.
Petunjuk / Saran
Untuk menemukan kapan fitur pertama kali diperkenalkan di C#, lihat artikel tentang riwayat versi bahasa C#.
Misalnya, Anda bisa mendeklarasikan kelas generik, AGenericClass, sehingga parameter T jenis mengimplementasikan IComparable<T> antarmuka:
public class AGenericClass<T> where T : IComparable<T> { }
Catatan
Untuk informasi selengkapnya tentang klausul where dalam ekspresi kueri, lihatlah klausul where.
Klausul where juga bisa mencakup batasan kelas dasar. Batasan kelas dasar menyatakan bahwa jenis yang akan digunakan sebagai argumen jenis untuk jenis generik tersebut memiliki kelas yang ditentukan sebagai kelas dasar, atau adalah kelas dasar tersebut. Jika Anda menggunakan batasan kelas dasar, batasan tersebut harus muncul sebelum batasan lain pada parameter jenis tersebut. Beberapa jenis tidak diizinkan sebagai batasan kelas dasar: Object, Array, dan ValueType. Contoh berikut menunjukkan jenis yang dapat Anda tentukan sebagai kelas dasar:
public class UsingEnum<T> where T : System.Enum { }
public class UsingDelegate<T> where T : System.Delegate { }
public class Multicaster<T> where T : System.MulticastDelegate { }
Dalam konteks nullable, kompilator memberlakukan nullability dari jenis kelas dasar. Jika kelas dasar tidak bisa diubah ke null (misalnya Base), argumen jenis harus tidak dapat diubah ke null. Jika kelas dasar dapat diubah ke null (misalnya Base?), argumen jenis dapat berupa jenis referensi nullable atau non-nullable. Pengkompilasi memberikan peringatan jika argumen jenis adalah jenis referensi yang dapat diubah ke null saat kelas dasar tidak dapat diubah ke null.
Klausa where bisa menentukan bahwa jenisnya adalah class atau struct. Batasan struct menghapus kebutuhan untuk menentukan batasan kelas dasar System.ValueType.
System.ValueType Jenis tidak dapat digunakan sebagai batasan kelas dasar. Contoh berikut ini menunjukkan batasan class dan struct :
class MyClass<T, U>
where T : class
where U : struct
{ }
Dalam konteks nullable, class batasan mengharuskan jenis menjadi jenis referensi yang tidak dapat diubah ke null. Untuk mengizinkan jenis referensi yang dapat diubah ke null, gunakan class? batasan, yang memungkinkan jenis referensi yang dapat diubah ke null dan yang tidak dapat diubah ke null.
Klausa where dapat mencakup batasan notnull . Batasan notnull membatasi parameter jenis ke jenis yang tidak dapat diubah ke null. Jenis dapat berupa jenis nilai atau jenis referensi yang tidak dapat diubah ke null. Batasan notnull tersedia untuk kode yang nullable enable dikompilasi dalam konteks. Tidak seperti batasan lainnya, jika argumen jenis melanggar batasan notnull, pengompilasi membuat peringatan alih-alih kesalahan. Peringatan hanya dihasilkan dalam konteks nullable enable.
Penambahan jenis referensi yang dapat diubah ke null memperkenalkan ambiguitas potensial dalam arti T? dalam metode generik. Jika T adalah struct, maka T? sama System.Nullable<T>dengan. Namun, jika T merupakan jenis referensi, T? berarti itu adalah nilai yang null valid. Ambiguitas hadir karena metode penimpaan tidak dapat mencakup batasan. Batasan default baru menyelesaikan ambiguitas ini. Tambahkan saat kelas dasar atau antarmuka mendeklarasikan dua kelebihan beban metode, satu yang menentukan struct batasan, dan yang tidak memiliki struct batasan atau class yang diterapkan:
public abstract class B
{
public void M<T>(T? item) where T : struct { }
public abstract void M<T>(T? item);
}
default Gunakan batasan untuk menentukan bahwa kelas turunan Anda mengambil alih metode tanpa batasan di kelas turunan Anda, atau implementasi antarmuka eksplisit. Ini hanya akan valid pada metode yang mengambil alih metode dasar, atau implementasi antarmuka eksplisit:
public class D : B
{
// Without the "default" constraint, the compiler tries to override the first method in B
public override void M<T>(T? item) where T : default { }
}
Penting
Anda dapat menggunakan deklarasi generik yang menyertakan notnull batasan dalam konteks terlupakan nullable, tetapi kompilator tidak memberlakukan batasan.
#nullable enable
class NotNullContainer<T>
where T : notnull
{
}
#nullable restore
Klausa where juga dapat menyertakan batasan unmanaged . Batasan unmanaged membatasi parameter jenis ke jenis yang dikenal sebagai jenis yang belum dikelola. Batasan unmanaged memudahkan untuk menulis kode interop tingkat rendah dalam C#. Batasan ini memungkinkan rutinitas yang bisa digunakan kembali di semua jenis yang tidak dikelola. Batasan unmanaged tidak dapat digabungkan dengan batasan class atau struct. Batasan unmanaged memaksa bahwa tipenya harus berupa struct:
class UnManagedWrapper<T>
where T : unmanaged
{ }
Klausul ini where juga dapat mencakup batasan konstruktor, new(). Batasan itu memungkinkan untuk membuat instans parameter jenis dengan menggunakan new operator.
Batasan new() memberi tahu kompiler bahwa argumen tipe apa pun yang diberikan harus memiliki konstruktor tanpa parameter yang dapat diakses. Contohnya:
public class MyGenericClass<T> where T : IComparable<T>, new()
{
// The following line is not possible without new() constraint:
T item = new T();
}
Batasan new() muncul terakhir dalam where klausul, kecuali diikuti oleh allows ref struct anti-batasan. Batasan new() tidak dapat digabungkan dengan batasan struct atau unmanaged. Semua tipe yang memenuhi batasan tersebut harus memiliki konstruktor tanpa parameter yang dapat diakses, membuat batasan new() menjadi berlebihan.
Anti-batasan ini menyatakan bahwa argumen jenis untuk T bisa menjadi ref struct jenis. Contohnya:
public class GenericRefStruct<T> where T : allows ref struct
{
// Scoped is allowed because T might be a ref struct
public void M(scoped T parm)
{
}
}
Jenis atau metode generik harus mematuhi aturan keamanan ref untuk instans T apa pun karena mungkin berupa ref struct. Klausa allows ref struct tidak dapat dikombinasikan dengan batasan class atau class? . Anti-batasan allows ref struct harus mengikuti semua batasan untuk argumen jenis tersebut.
Dengan beberapa parameter tipe, gunakan satu klausul where untuk setiap parameter tipe, misalnya:
public interface IMyInterface { }
namespace CodeExample
{
class Dictionary<TKey, TVal>
where TKey : IComparable<TKey>
where TVal : IMyInterface
{
public void Add(TKey key, TVal val) { }
}
}
Anda juga dapat melampirkan batasan ke parameter tipe metode generik, seperti yang ditunjukkan pada contoh berikut:
public void MyMethod<T>(T t) where T : IMyInterface { }
Sintaks untuk menjelaskan batasan parameter jenis pada delegasi sama dengan metode:
delegate T MyDelegate<T>() where T : new();
Untuk informasi tentang delegasi generik, lihatlah Delegasi Generik.
Untuk detail tentang sintaksis dan penggunaan batasan, lihatlah Batasan pada Parameter Jenis.
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat Spesifikasi Bahasa C#. Spesifikasi bahasa adalah sumber definitif untuk sintaks dan penggunaan C#.