Jak przeciążać operatora nawiasu kwadratowego w C #?

254

Na przykład DataGridView pozwala to zrobić:

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

ale przez całe życie nie mogę znaleźć dokumentacji operatora indeksu / nawiasu kwadratowego. Jak oni to nazywają? Gdzie to jest realizowane? Czy to może rzucić? Jak mogę zrobić to samo na własnych zajęciach?

ETA: Dzięki za wszystkie szybkie odpowiedzi. W skrócie: odpowiednia dokumentacja należy do właściwości „Przedmiot”; sposobem na przeciążenie jest zadeklarowanie właściwości takiej jak public object this[int x, int y]{ get{...}; set{...} }; moduł indeksujący dla DataGridView nie zgłasza, przynajmniej zgodnie z dokumentacją. Nie wspomina o tym, co się stanie, jeśli podasz nieprawidłowe współrzędne.

ETA Znowu: OK, chociaż dokumentacja nie wspomina o tym (niegrzeczny Microsoft!), Okazuje się, że indeksator DataGridView w rzeczywistości wyrzuci ArgumentOutOfRangeException, jeśli podasz mu nieprawidłowe współrzędne. Uczciwe ostrzeżenie.

Coderer
źródło

Odpowiedzi:

374

można znaleźć jak to zrobić tutaj . W skrócie jest to:

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

Jeśli potrzebujesz tylko gettera, możesz również użyć składni w odpowiedzi poniżej (zaczynając od C # 6).

Ruben
źródło
9
drobny komentarz: w zależności od tego, co robisz, bardziej odpowiednie może być: get {return base [i]; } set {base [i] = wartość; }
MikeBaz - MSFT
7
To nie jest przeciążanie operatora. Jest indeksatorem
Destructor
5
Indeksator może być również jednostronnym operatorem.
alan2here
1
W 2019 r. Należy wybrać nową odpowiedź, . Szkoda, że ​​SO nie ma opcji radzenia sobie z przestarzałymi odpowiedziami, ponieważ nowa nie jest bliska uzyskania ponad 350 głosów pozytywnych, choć na to zasługuje.
min.
@mins Dołączyłem link do innej odpowiedzi.
Ruben
41

To byłaby właściwość elementu: http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Może coś takiego działałoby:

public T Item[int index, int y]
{ 
    //Then do whatever you need to return/set here.
    get; set; 
}
Ricardo Villamil
źródło
Wielkie dzięki! Gdybym mógł ustawić dwie odpowiedzi, dodałbym również twoją - nikt inny nie wiedział, aby poszukać przedmiotu w dokumentacji ...
Coderer,
5
Pod względem sposobu implementacji jest to „Przedmiot”, ale w języku C # jest to „to”
Marc Gravell
1
Zgadza się, ale zapytałem „przez całe życie nie mogę znaleźć dokumentacji dotyczącej operatora indeksu / nawiasu kwadratowego” - miałem na myśli, gdy przeglądasz klasę biblioteki w MSDN, gdzie mówią ci o operatorze? Dlatego zrobiłem ostatnią „ETA” o tym, co rzuca - dokumenty są błędne .
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!

Źródło informacji

Do wspornika:

public Object this[int index]
{

}

ALE

Operatora indeksowania tablic nie można przeciążać ; jednak typy mogą definiować indeksatory, właściwości, które przyjmują jeden lub więcej parametrów. Parametry indeksatora są ujęte w nawiasy kwadratowe, podobnie jak indeksy tablicowe, ale parametry indeksatora można zadeklarować jako dowolnego typu (w przeciwieństwie do indeksów tablicowych, które muszą być integralne).

Z MSDN

Patrick Desjardins
źródło
tak, może być przeciążony, o ile sygnatura parametru jest inna, dokładnie tak, jak w przypadku innych metod przeciążania
Charles Bretana,
Może, ale nie w przypadku warunku, który napisałem. Pochodzi z MSDN. Sprawdź źródło, jeśli mi nie wierzysz
Patrick Desjardins,
1
Przepraszam, jeśli źle przeczytałem Twój post, ale do jakiego stanu się odnosisz?
Charles Bretana,
+1 za przydatną listę. FYI link umarł. (4 lata później, wiem)
Mixxiphoid
Chciałbym dodać, że możesz zastąpić zarówno rzutowanie jawne, jak i jawne w C #.
Felype,
9

Jeśli używasz C # 6 lub nowszej wersji, możesz użyć składni wyrażającej treści dla indeksatora get-only:

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

amoss
źródło
6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}
Jason Miesionczek
źródło
5
W rzeczywistości jest to naprawdę niebezpieczne - masz teraz dwie konkurencyjne implementacje: każda ze zmienną o typie List <T> lub IList <T> lub IList itp. Nie wykona Twojego kodu niestandardowego.
Marc Gravell
1
Zgadzam się - jeśli nic więcej, nie trzeba uzyskiwać kolekcji niestandardowej z listy, ale nie zdawałem sobie sprawy, że to naprawdę niebezpieczne
Coderer
Nadal jednak będzie wykonywać niestandardowy kod, prawda? Nie ma znaczenia, jaki typ zmiennej deklarujesz - liczy się typ obiektu.
izb
1
Przyjazne przypomnienie polimorfizmu C #: Dzieje się tak, ponieważ klasa podstawowa nie deklaruje swojej implementacji jako wirtualnej. Gdyby został zadeklarowany jako wirtualny, kod niestandardowy zostałby wywołany w każdym przypadku.
almulo
1
Ponadto ten kod wyświetli ostrzeżenie kompilatora, ponieważ oba indeksatory nie są wirtualne. Kompilator zasugeruje, że kwalifikujesz niestandardowy indeksator newsłowem kluczowym.
amoss
4

W przypadku CLI C ++ (skompilowanego z / clr) zobacz to łącze MSDN .

Krótko mówiąc, właściwość może otrzymać nazwę „default”:

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

źródło
2

Oto przykład zwracający wartość z wewnętrznego obiektu List. Powinien dać ci pomysł.

  public object this[int index]
  {
     get { return ( List[index] ); }
     set { List[index] = value; }
  }
Rob Prouse
źródło
1

Jeśli masz na myśli indeksatora tablic, przeciążasz go, pisząc właściwość indeksatora. I możesz przeciążać (zapisywać tyle, ile chcesz) właściwości indeksatora, o ile każda z nich ma inną sygnaturę parametru

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
źródło
2
Po pierwsze, masz na myśli to [], a nie to () - jednak dostarczenie niestandardowego (ale innego) tego [int] na czymś, co jest listą (IList / IList <T> / List <T>) jest dość niebezpieczne - i może prowadzić do subtelnych błędów między wersjami „int index” i „int workerId”. Oba są nadal na żądanie.
Marc Gravell
i tak naprawdę nie sądzę, że kod, który wprowadziłem powyżej, skompilowałby się bez dodawania nowego lub zastąpienia instrukcji właśnie z powodu istnienia implementacji List <T> tego [int]. Masz rację co do potencjału, robiąc to, po prostu oznaczało to jako przykład przeciążenia indeksatora.
Charles Bretana,