Bagaimana cara membebani operator braket persegi di C #?

254

DataGridView, misalnya, memungkinkan Anda melakukan ini:

DataGridView dgv = ...;
DataGridViewCell cell = dgv[1,5];

tetapi untuk kehidupan saya, saya tidak dapat menemukan dokumentasi pada operator index / square-bracket. Mereka menyebutnya apa? Di mana itu diterapkan? Bisakah itu melempar? Bagaimana saya bisa melakukan hal yang sama di kelas saya sendiri?

ETA: Terima kasih atas semua jawaban cepatnya. Secara singkat: dokumentasi yang relevan berada di bawah properti "Item"; cara untuk membebani adalah dengan mendeklarasikan properti seperti public object this[int x, int y]{ get{...}; set{...} }; pengindeks untuk DataGridView tidak melempar, setidaknya sesuai dengan dokumentasi. Tidak disebutkan apa yang terjadi jika Anda memberikan koordinat yang tidak valid.

ETA Sekali lagi: OK, meskipun dokumentasi tidak menyebutkannya (Microsoft nakal!), Ternyata pengindeks untuk DataGridView sebenarnya akan melempar ArgumentOutOfRangeException jika Anda menyediakannya dengan koordinat yang tidak valid. Peringatan yang adil.

Pembuat kode
sumber

Jawaban:

374

Anda dapat menemukan cara melakukannya di sini . Singkatnya itu adalah:

public object this[int i]
{
    get { return InnerList[i]; }
    set { InnerList[i] = value; }
}

Jika Anda hanya memerlukan pengambil, sintaks dalam jawaban di bawah ini dapat digunakan juga (mulai dari C # 6).

Ruben
sumber
9
komentar minor: tergantung pada apa yang Anda lakukan, Anda mungkin merasa lebih tepat untuk melakukan: get {return base [i]; } set {base [i] = value; }
MikeBaz - MSFT
7
Ini bukan kelebihan operator. Ini adalah pengindeks
Destructor
5
Pengindeks, mungkin juga operator unary.
alan2here
1
Pada 2019, jawaban baru harus dipilih, yang ini . Sayang sekali SO tidak memiliki fitur untuk berurusan dengan jawaban yang sudah ketinggalan zaman, karena yang baru tidak dekat untuk mendapatkan 350+ upvotes, meskipun layak mendapatkannya.
mnt
@ admin Saya menyertakan tautan ke jawaban lain.
Ruben
41

Itu akan menjadi properti item: http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Mungkin sesuatu seperti ini akan berhasil:

public T Item[int index, int y]
{ 
    //Then do whatever you need to return/set here.
    get; set; 
}
Ricardo Villamil
sumber
Terima kasih banyak! Jika saya dapat menetapkan dua jawaban, saya juga akan menambahkan jawaban Anda - tidak ada orang lain yang tahu untuk mencari Item dalam dokumentasi ...
Coderer
5
Dalam hal bagaimana itu diterapkan, itu adalah "Item", tetapi dalam istilah C #, itu adalah "ini"
Marc Gravell
1
Benar, tetapi saya bertanya "untuk kehidupan saya, saya tidak dapat menemukan dokumentasi pada operator indeks / braket persegi" - Maksud saya ketika Anda mencari kelas perpustakaan di MSDN, di mana mereka memberi tahu Anda tentang operator? Itu sebabnya saya membuat "ETA" terakhir tentang apa yang dilemparnya - dokumen salah .
Coderer
26
Operators                           Overloadability

+, -, *, /, %, &, |, <<, >>         All C# binary operators can be overloaded.

+, -, !,  ~, ++, --, true, false    All C# unary operators can be overloaded.

==, !=, <, >, <= , >=               All relational operators can be overloaded, 
                                    but only as pairs.

&&, ||                  They can't be overloaded

() (Conversion operator)        They can't be overloaded

+=, -=, *=, /=, %=                  These compound assignment operators can be 
                                    overloaded. But in C#, these operators are
                                    automatically overloaded when the respective
                                    binary operator is overloaded.

=, . , ?:, ->, new, is, as, sizeof  These operators can't be overloaded

    [ ]                             Can be overloaded but not always!

Sumber informasinya

Untuk braket:

public Object this[int index]
{

}

TAPI

Operator pengindeksan array tidak dapat kelebihan beban ; Namun, tipe dapat mendefinisikan pengindeks, properti yang mengambil satu atau lebih parameter. Parameter pengindeks terlampir dalam tanda kurung siku, sama seperti indeks larik, tetapi parameter pengindeks dapat dinyatakan dari jenis apa pun (tidak seperti indeks larik, yang harus integral).

Dari MSDN

Patrick Desjardins
sumber
ya itu bisa kelebihan beban, selama parameter tanda tangan berbeda, persis seperti pembatasan kelebihan metode lain
Charles Bretana
Bisa, tetapi tidak untuk kondisi yang saya tulis. Ini dari MSDN. Periksa sumbernya jika Anda tidak percaya
Patrick Desjardins
1
Maaf jika saya salah membaca posting Anda, tetapi apa kondisi yang Anda maksud?
Charles Bretana
+1 untuk daftar praktis. FYI tautannya mati. (4 tahun kemudian, saya tahu)
Mixxiphoid
Saya ingin menambahkan bahwa Anda dapat mengesampingkan pengecoran tipe implisit dan eksplisit di C # sekarang.
Felype
9

Jika Anda menggunakan C # 6 atau lebih baru, Anda bisa menggunakan sintaks bertubuh ekspresi untuk pengindeks get-only:

public object this[int i] => this.InnerList[i];

amoss
sumber
6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}
Jason Miesionczek
sumber
5
Sebenarnya, ini sangat berbahaya - Anda sekarang memiliki dua implementasi yang bersaing: siapa pun dengan variabel yang diketikkan sebagai Daftar <T> atau IList <T> atau IList dll tidak akan menjalankan kode khusus Anda.
Marc Gravell
1
Setuju - jika tidak ada yang lain, itu tidak perlu untuk mendapatkan CustomCollection Anda dari Daftar, tapi saya tidak menyadari itu sebenarnya berbahaya
Coderer
Itu masih akan mengeksekusi kode kustom, bukan? Tidak masalah tipe variabel apa yang Anda deklarasikan - itu jenis objek yang penting.
izb
1
Pengingat ramah polimorfisme C #: Itu terjadi karena kelas dasar tidak menyatakan implementasinya sebagai virtual. Jika dinyatakan sebagai virtual, kode khusus akan dipanggil dalam setiap kasus.
almulo
1
Juga, kode ini akan memberi Anda peringatan kompiler karena kedua pengindeks non-virtual. Kompiler akan menyarankan agar Anda memenuhi syarat pengindeks kustom Anda dengan newkata kunci.
Amoss
4

Untuk CLI C ++ (dikompilasi dengan / clr) lihat tautan MSDN ini .

Singkatnya, sebuah properti dapat diberi nama "default":

ref class Class
{
 public:
  property System::String^ default[int i]
  {
    System::String^ get(int i) { return "hello world"; }
  }
};

sumber
2

Berikut adalah contoh mengembalikan nilai dari objek Daftar internal. Harus memberi Anda ide.

  public object this[int index]
  {
     get { return ( List[index] ); }
     set { List[index] = value; }
  }
Rob Prouse
sumber
1

Jika maksud Anda adalah pengindeks array, Anda kelebihan itu hanya dengan menulis properti pengindeks .. Dan Anda dapat membebani, (tulis sebanyak yang Anda inginkan) properti pengindeksan asalkan masing-masing memiliki parameter tanda tangan yang berbeda

public class EmployeeCollection: List<Employee>
{
    public Employee this[int employeeId]
    {   
        get 
        { 
            foreach(var emp in this)
            {
                if (emp.EmployeeId == employeeId)
                    return emp;
            }

            return null;
        }
    }

    public Employee this[string employeeName]
    {   
        get 
        { 
            foreach(var emp in this)
            {
                if (emp.Name == employeeName)
                    return emp;
            }

            return null;
        }
    }
}
Charles Bretana
sumber
2
Pertama, maksud Anda [] ini, bukan ini () - namun, memberikan kebiasaan (tetapi berbeda) [int] ini pada sesuatu yang merupakan daftar (IList / IList <T> / List <T>) cukup berbahaya - dan dapat menyebabkan bug halus antara versi "int index" dan "int employeeId". Keduanya masih bisa dihubungi.
Marc Gravell
dan pada kenyataannya, saya tidak berpikir kode yang saya masukkan di atas akan dikompilasi tanpa menambahkan pernyataan baru atau menimpa justru karena keberadaan Daftar <T> implementasi [int] ini. Anda benar tentang potensi ketika melakukan ini, cukup beri contoh pengindeksan yang berlebihan.
Charles Bretana