¿Cómo sobrecargo el operador de corchetes en C #?

254

DataGridView, por ejemplo, le permite hacer esto:

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

pero por mi vida no puedo encontrar la documentación sobre el operador de índice / corchete. ¿Cómo lo llaman? ¿Dónde se implementa? Puede lanzar? ¿Cómo puedo hacer lo mismo en mis propias clases?

ETA: Gracias por todas las respuestas rápidas. Brevemente: la documentación relevante se encuentra bajo la propiedad "Artículo"; la forma de sobrecargar es declarando una propiedad como public object this[int x, int y]{ get{...}; set{...} }; el indexador para DataGridView no se lanza, al menos de acuerdo con la documentación. No menciona lo que sucede si proporciona coordenadas no válidas.

ETA nuevamente: OK, aunque la documentación no lo menciona (¡travieso Microsoft!), Resulta que el indexador para DataGridView de hecho arrojará una ArgumentOutOfRangeException si le proporciona coordenadas no válidas. Advertencia justa.

Coderer
fuente

Respuestas:

374

Puedes encontrar cómo hacerlo aquí . En resumen es:

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

Si solo necesita un captador, la sintaxis en la respuesta a continuación también se puede usar (a partir de C # 6).

Rubén
fuente
99
un comentario menor: dependiendo de lo que esté haciendo, puede que le resulte más apropiado: get {return base [i]; } set {base [i] = valor; }
MikeBaz - MSFT
77
Esto no es sobrecarga del operador. Es indexador
Destructor
55
Indexador, también puede ser un operador unario.
alan2here
1
En 2019, se debe seleccionar una nueva respuesta, esta . Lástima que SO no tenga una función para lidiar con respuestas obsoletas, ya que la nueva no está cerca de obtener más de 350 votos a favor, aunque los merece.
minutos
@mins Incluí un enlace a la otra respuesta.
Ruben
41

Esa sería la propiedad del elemento: http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Tal vez algo como esto funcionaría:

public T Item[int index, int y]
{ 
    //Then do whatever you need to return/set here.
    get; set; 
}
Ricardo Villamil
fuente
¡Muchas gracias! Si pudiera establecer dos respuestas, también agregaría la suya: nadie más sabía buscar el ítem en la documentación ...
Coderer el
55
En términos de cómo se implementa, es "Elemento", pero en términos de C #, es "esto"
Marc Gravell
1
Correcto, pero pregunté "por mi vida no puedo encontrar la documentación sobre el operador de índice / corchete". Me refiero a cuando buscas una clase de biblioteca en MSDN, ¿dónde te informan sobre el operador? Es por eso que hice esa última "ETA" sobre lo que arroja: los documentos están equivocados .
Coderer el
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!

Fuente de la información

Para soporte:

public Object this[int index]
{

}

PERO

El operador de indexación de matriz no se puede sobrecargar ; sin embargo, los tipos pueden definir indexadores, propiedades que toman uno o más parámetros. Los parámetros del indexador están encerrados entre corchetes, al igual que los índices de matriz, pero los parámetros de indexación pueden declararse de cualquier tipo (a diferencia de los índices de matriz, que deben ser integrales).

De MSDN

Patrick Desjardins
fuente
sí, se puede sobrecargar, siempre que la firma del parámetro sea diferente, exactamente como las restricciones de sobrecarga de cualquier otro método
Charles Bretana
Puede, pero no por la condición que escribí. Es de MSDN. Compruebe la fuente si no me cree
Patrick Desjardins
1
Lo siento si leí mal tu publicación, pero ¿a qué condición te refieres?
Charles Bretana el
+1 para la lista práctica. FYI el enlace murió. (4 años después, lo sé)
Mixxiphoid
Me gustaría agregar que ahora puede anular la conversión de tipos implícita y explícita en C #.
Felype
9

Si está utilizando C # 6 o posterior, puede usar la sintaxis con cuerpo de expresión para el indexador get-only:

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

amoss
fuente
6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}
Jason Miesionczek
fuente
55
En realidad, esto es realmente peligroso: ahora tiene dos implementaciones competidoras: cualquier persona con una variable escrita como List <T> o IList <T> o IList, etc., no ejecutará su código personalizado.
Marc Gravell
1
De acuerdo, si nada más, no es necesario derivar su CustomCollection de List, pero no me había dado cuenta de que en realidad era peligroso
Coderer
Sin embargo, seguirá ejecutando el código personalizado, ¿no? No importa qué tipo de variable declares: lo que importa es el tipo de objeto.
izb
1
Recordatorio amistoso del polimorfismo de C #: eso sucede porque la clase base no declara su implementación como virtual. Si se declarara virtual, se llamaría al código personalizado en todos los casos.
almulo
1
Además, este código le dará una advertencia del compilador ya que ambos indexadores no son virtuales. El compilador le sugerirá que califique su indexador personalizado con la newpalabra clave.
amoss
4

Para CLI C ++ (compilado con / clr) vea este enlace de MSDN .

En resumen, a una propiedad se le puede dar el nombre "predeterminado":

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

fuente
2

Aquí hay un ejemplo que devuelve un valor de un objeto List interno. Debería darte la idea.

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

Si te refieres al indexador de matrices, lo sobrecargas con solo escribir una propiedad del indexador ... Y puedes sobrecargar, (escribe tantas como quieras) propiedades del indexador siempre que cada una tenga una firma de parámetro diferente

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
fuente
2
Primero, quiere decir esto [], no esto (); sin embargo, proporcionar una costumbre (pero diferente) esto [int] en algo que es una lista (IList / IList <T> / List <T>) es bastante peligroso, y podría generar errores sutiles entre las versiones "int index" y "int employeeId". Ambos todavía son invocables.
Marc Gravell
y de hecho, no creo que el código que ingresé arriba se compile sin agregar una nueva declaración o anular precisamente debido a la existencia de la implementación List <T> de este [int]. Tienes razón sobre el potencial al hacer esto, simplemente lo entendiste como un ejemplo de sobrecarga del indexador.
Charles Bretana el