1 - What are indexers in C#
The indexers
are a property that allows us to work with an object as if it were an array
.
The Microsoft documentation tells us the following: "Indexers allow instances of a class or struct to be indexed just like arrays"
When we define an indexer for a class, that class will behave as a virtual array.
Remember that to access elements in an array, we use [index]
. By using its indexer, we can assign values or receive the object as such.
2 - How to define an indexer in C#
Defining an indexer is as simple as the following:
[modificador_acceso] [tipo_return] this [index]
{
get
{
return x[index]
}
set
{
x[index] = value;
}
}
As we can see, an indexer must contain the following terms:
- Access modifier: it can be public, private, protected, or internal. If you need more information about access modifiers, you can get it at this link
- Return type: any type in C# is valid.
- this: keyword that points to the current class object.
- index: this specifies the element in the list we are going to access. It doesn't have to be an integer as we usually do in arrays, it can be any data type.
- get, set : accessors for the elements.
- When assigning a value, we do it through the
value
keyword.
3 - Example of an indexer in C#
As an example, we can use the one available in the CSV library on github, specifically the class where each of the rows is read, basically this is the code:
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;
}
}
As we can see, we have two indexers in this class. One for string
type and another for int
type, which tells us that we can use overloading with indexers.
public dynamic this[int index] => //Code
public dynamic this[string searchField] => //Code
And then to call the indexer, we have both options. In the specific case of the CSV library, the indexer indicates the column we are going to access, either by column name or its position in the file.
csvRow[1];
csvRow["statecode"];
To access or use the indexer, we can do it as follows. To replicate the scenario, I've created a test called TestIndexerYoutube
. In this test, we access a row from the CSV, and once we have the row, we access its elements using the indexer.
[TestMethod]
public void TestIndexerYoutube()
{
var insuranceRow = Csv.Rows.FirstOrDefault();
var countryIndexerInt = insuranceRow[1];
var countryIndexerString = insuranceRow["statecode"];
Assert.AreEqual(countryIndexerInt, countryIndexerString);
}
4 - Key points when using indexers
- We've seen single dimension indexers, but we can also have multidimensional ones:
public dynamic this[string searchField, string searchField2]
- As we've seen, we can use overloading on indexers.
- Indexers allow us to index objects in a way similar to arrays.
- The keyword this is required when using indexers.
- When assigning a value through an indexer, remember to use the keyword value
- Indexers cannot be static members.
If there is any problem you can add a comment bellow or contact me in the website's contact form