Wie überlade ich den eckigen Operator in C #?

254

Mit DataGridView können Sie beispielsweise Folgendes tun:

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

aber für mein Leben kann ich die Dokumentation zum Index- / eckigen Klammeroperator nicht finden. Wie nennen sie es? Wo ist es implementiert? Kann es werfen? Wie kann ich dasselbe in meinen eigenen Klassen tun?

ETA: Danke für all die schnellen Antworten. Kurz gesagt: Die entsprechende Dokumentation befindet sich unter der Eigenschaft "Artikel". Der Weg zur Überlastung besteht darin, eine Eigenschaft wie zu deklarieren public object this[int x, int y]{ get{...}; set{...} }. Der Indexer für DataGridView löst zumindest laut Dokumentation nicht. Es wird nicht erwähnt, was passiert, wenn Sie ungültige Koordinaten angeben.

Nochmals ETA: OK, obwohl die Dokumentation dies nicht erwähnt (ungezogenes Microsoft!), Stellt sich heraus, dass der Indexer für DataGridView tatsächlich eine ArgumentOutOfRangeException auslöst, wenn Sie ungültige Koordinaten angeben. Faire Warnung.

Codierer
quelle

Antworten:

374

Wie das geht, finden Sie hier . Kurz gesagt ist es:

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

Wenn Sie nur einen Getter benötigen, kann auch die Syntax in der Antwort unten verwendet werden (ab C # 6).

Ruben
quelle
9
ein kleiner Kommentar: Je nachdem, was Sie tun, ist es möglicherweise angemessener, Folgendes zu tun: get {return base [i]; } set {base [i] = value; }
MikeBaz - MSFT
7
Dies ist keine Überlastung des Bedieners. Es ist Indexer
Destructor
5
Indexer kann auch ein unärer Operator sein.
Alan2here
1
2019 sollte eine neue Antwort ausgewählt werden, diese . Schade, dass SO keine Funktion hat, um mit veralteten Antworten umzugehen, da die neue nicht in der Nähe ist, um mehr als 350 Upvotes zu erhalten, obwohl sie diese verdient.
Minuten
@mins Ich habe einen Link zur anderen Antwort eingefügt.
Ruben
41

Das wäre die Item-Eigenschaft: http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Vielleicht würde so etwas funktionieren:

public T Item[int index, int y]
{ 
    //Then do whatever you need to return/set here.
    get; set; 
}
Ricardo Villamil
quelle
Vielen Dank! Wenn ich zwei Antworten setzen könnte, würde ich auch Ihre hinzufügen - niemand sonst wusste, dass er in der Dokumentation nach Artikel suchen sollte ...
Coderer
5
In Bezug auf die Implementierung ist es "Item", aber in C # ist es "this"
Marc Gravell
1
Richtig, aber ich fragte "für mein Leben kann ich die Dokumentation zum Index- / eckigen Klammeroperator nicht finden" - ich meinte, wenn Sie eine Bibliotheksklasse in MSDN nachschlagen, wo erzählen sie Ihnen über den Operator? Deshalb habe ich das letzte "ETA" über das gemacht, was es wirft - die Dokumente sind falsch .
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!

Informationsquelle

Für Klammer:

public Object this[int index]
{

}

ABER

Der Array-Indizierungsoperator kann nicht überladen werden . Typen können jedoch Indexer definieren, Eigenschaften, die einen oder mehrere Parameter annehmen. Indexerparameter sind wie Array-Indizes in eckigen Klammern eingeschlossen, aber Indexer-Parameter können als beliebig deklariert werden (im Gegensatz zu Array-Indizes, die ganzzahlig sein müssen).

Von MSDN

Patrick Desjardins
quelle
Ja, es kann überladen werden, solange die Parametersignatur unterschiedlich ist, genau wie die Überlastungsbeschränkungen jeder anderen Methode
Charles Bretana
Es kann, aber nicht für den Zustand, den ich geschrieben habe. Es ist von MSDN. Überprüfen Sie die Quelle, wenn Sie mir nicht glauben
Patrick Desjardins
1
Es tut mir leid, wenn ich Ihren Beitrag falsch gelesen habe, aber auf welche Bedingung beziehen Sie sich?
Charles Bretana
+1 für die handliche Liste. Zu Ihrer Information, der Link ist gestorben. (4 Jahre später, ich weiß)
Mixxiphoid
Ich möchte hinzufügen, dass Sie jetzt sowohl implizites als auch explizites Typ-Casting in C # überschreiben können.
Felype
9

Wenn Sie C # 6 oder höher verwenden, können Sie die Ausdruckssyntax für den Nur-Get-Indexer verwenden:

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

amoss
quelle
6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}
Jason Miesionczek
quelle
5
Eigentlich ist das sehr gefährlich - Sie haben jetzt zwei konkurrierende Implementierungen: Jeder mit einer Variablen wie List <T> oder IList <T> oder IList usw. führt Ihren benutzerdefinierten Code nicht aus.
Marc Gravell
1
Einverstanden - wenn nichts anderes, ist es nicht notwendig, Ihre CustomCollection von List abzuleiten, aber ich hatte nicht
bemerkt,
Der benutzerdefinierte Code wird trotzdem ausgeführt, nicht wahr? Es spielt keine Rolle, welchen Variablentyp Sie deklarieren - es ist der Typ des Objekts, der zählt.
izb
1
Freundliche Erinnerung an C # -Polymorphismus: Dies geschieht, weil die Basisklasse ihre Implementierung nicht als virtuell deklariert. Wenn es als virtuell deklariert würde, würde der benutzerdefinierte Code in jedem Fall aufgerufen.
Almulo
1
Dieser Code gibt Ihnen auch eine Compiler-Warnung, da beide Indexer nicht virtuell sind. Der Compiler schlägt vor, dass Sie Ihren benutzerdefinierten Indexer mit dem newSchlüsselwort qualifizieren.
Amoss
4

Informationen zu CLI C ++ (kompiliert mit / clr) finden Sie unter diesem MSDN-Link .

Kurz gesagt, eine Eigenschaft kann den Namen "Standard" erhalten:

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

quelle
2

Hier ist ein Beispiel, das einen Wert von einem internen Listenobjekt zurückgibt. Sollte Ihnen die Idee geben.

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

Wenn Sie den Array-Indexer meinen, überladen Sie dies, indem Sie einfach eine Indexer-Eigenschaft schreiben. Und Sie können Indexer-Eigenschaften überladen (so viele schreiben, wie Sie möchten), solange jede eine andere Parametersignatur hat

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
quelle
2
Zunächst meinen Sie dies [], nicht this () - es ist jedoch ziemlich gefährlich, ein benutzerdefiniertes (aber anderes) [int] für etwas bereitzustellen, das eine Liste ist (IList / IList <T> / List <T>) - und kann zu subtilen Fehlern zwischen den Versionen "int index" und "int employeeId" führen. Beide sind noch aufrufbar.
Marc Gravell
Tatsächlich glaube ich nicht, dass der oben eingegebene Code kompiliert werden würde, ohne eine neue oder überschreibende Anweisung hinzuzufügen, gerade weil die List <T> -Implementierung dieses [int] vorhanden ist. Sie haben Recht mit dem Potenzial, wenn Sie dies tun, und meinten es einfach als Beispiel für das Überladen des Indexers.
Charles Bretana