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.

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).


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; 
}

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


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];


6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}

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"; }
  }
};

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; }
  }

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;
        }
    }
}

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.