1 - Qué son los indexers en C#
Los indexers
son una propiedad que nos permite trabajar con un objeto como si fuera un array
.
La documentación de Microsoft nos indica lo siguiente: “Los indexers permiten instancias de clases o strucs ser indexadas como arrays”
Cuando definimos un indexer para una clase, esa clase actuará como un array virtual.
Recuerda que para acceder a los elementos de un array lo hacemos con [index]
. Utilizando su indexer podemos asignarle valor o recibir el objetos como tal.
2 - Cómo definir un indexer en C#
Para definir un indexer es tan sencillo como lo siguiente:
[modificador_acceso] [tipo_return] this [index]
{
get
{
return x[index]
}
set
{
x[index] = value;
}
}
Como vemos, un indexer debe contener los siguientes términos:
- Modificador de acceso: puede ser público, privado, protected o internal. si necesitas más información sobre los modificadores de acceso, puedes obtenerla en este link
- Tipo de retorno: cualquier tipo en C# es válido.
- this: palabra clave que apunta al objeto de la clase actual.
- index: indicamos el elemento de la lista al que vamos a acceder. no tiene porque ser un entero como hacemos en los arrays, puede ser cualquier tipo de dato.
- get, set : propiedades de acceso a los elementos.
- cuando asignamos valor, lo hacemos a través de la palabra clave
value
.
3 - Ejemplo de indexer en C#
Como ejemplo podemos utilizar el ejemplo que tengo en la librería de CSV en github, en concreto la clase donde leemos de cada una de las filas basicamente este es el código:
public class CsvRow
{
internal List<CsvField> FieldValue { get; set; }
/// <summary>
/// Get row information by index
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public dynamic this[int index] => GetFieldByPosition(index);
/// <summary>
/// Get row information by headername
/// </summary>
/// <param name="searchField"></param>
/// <returns></returns>
public dynamic this[string searchField] => GetFieldByString(searchField);
public CsvRow()
{
FieldValue = new List<CsvField>();
}
private dynamic GetFieldByPosition(int position)
{
return FieldValue.ElementAt(position).Value.ToString();
}
private dynamic GetFieldByString(string searchField)
{
return FieldValue.First(a => a.Field.ToUpper() == searchField.ToUpper()).Value;
}
}
Como vemos disponemos de dos indexers en esta clase. Uno por tipo string
, y otro por tipo int
, lo cual nos indica que podemos utilzar sobreescritura en los indexers.
public dynamic this[int index] => //Codigo
public dynamic this[string searchField] => //Codigo
Y posteriormente para ejecutar la llamada al indexer tenemos ambas opciones. En el caso concreto de la librería de CSV el indexer indica la columna a la que vamos a acceder, ya sea mediante el nombre de la columna, o su posición en el fichero.
csvRow[1];
csvRow["statecode"];
Para acceder o ejecutar el indexer lo podemos hacer de la siguiente manera, para replicar el escenario, he creado un test un test llamado TestIndexerYoutube
, en este test accedemos a una de las filas del CSV y una vez tenemos las fila, accedemos a sus elementos utilizando el indexer.
[TestMethod]
public void TestIndexerYoutube()
{
var insuranceRow = Csv.Rows.FirstOrDefault();
var countryIndexerInt = insuranceRow[1];
var countryIndexerString = insuranceRow["statecode"];
Assert.AreEqual(countryIndexerInt, countryIndexerString);
}
4 - Puntos clave cuando utilizamos indexers
- Hemos visto indexers de una dimensión, pero también podemos tener multidimensionales:
public dynamic this[string searchField, string searchField2]
- Como hemos visto, podemos hacer sobrecarga en los indexers.
- Los indexers nos permiten indexar objetos de una forma similar a los arrays .
- La palabra clave this es obligatoria cuando utilizamos indexers.
- Cuando asignamos valor a través de un indexer debemos utilizar la palabra clave value
- Los indexers no pueden ser miembros estáticos.