Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to use indexers in C# 8.0?
Indexers in C# allow objects to be accessed like arrays using the square bracket notation. C# 8.0 introduced the index from end operator (^) which provides a more intuitive way to access elements from the end of a collection or sequence.
The ^ operator returns an index that is relative to the end of the sequence, making it the most compact and easiest way to access end elements compared to traditional methods like array.Length - 1.
Syntax
Following is the syntax for defining an indexer in a class −
public returnType this[parameterType parameter] {
get { return value; }
set { /* assign value */ }
}
Following is the syntax for using the index from end operator −
collection[^n] // Gets the nth element from the end collection[^1] // Gets the last element collection[^2] // Gets the second-to-last element
How Index from End Operator Works
Using Custom Indexers with Index from End Operator
Example
using System;
using System.Collections.Generic;
using System.Linq;
public class Employee {
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
}
public class Company {
public List<Employee> listEmployees;
public Company() {
listEmployees = new List<Employee>();
listEmployees.Add(new Employee { EmployeeId = 1, Name = "Alice", Gender = "Female" });
listEmployees.Add(new Employee { EmployeeId = 2, Name = "Bob", Gender = "Male" });
listEmployees.Add(new Employee { EmployeeId = 3, Name = "Charlie", Gender = "Male" });
listEmployees.Add(new Employee { EmployeeId = 4, Name = "Diana", Gender = "Female" });
listEmployees.Add(new Employee { EmployeeId = 5, Name = "Eve", Gender = "Female" });
listEmployees.Add(new Employee { EmployeeId = 6, Name = "Frank", Gender = "Male" });
listEmployees.Add(new Employee { EmployeeId = 7, Name = "Grace", Gender = "Female" });
listEmployees.Add(new Employee { EmployeeId = 8, Name = "Henry", Gender = "Male" });
}
public string this[int employeeId] {
get {
return listEmployees.FirstOrDefault(x => x.EmployeeId == employeeId)?.Name;
}
set {
var employee = listEmployees.FirstOrDefault(x => x.EmployeeId == employeeId);
if (employee != null) {
employee.Name = value;
}
}
}
}
class Program {
public static void Main() {
Company company = new Company();
Console.WriteLine("Using custom indexer:");
Console.WriteLine("Employee with Id = 2: " + company[2]);
Console.WriteLine("Employee with Id = 5: " + company[5]);
Console.WriteLine("Employee with Id = 8: " + company[8]);
Console.WriteLine("\nUsing index from end operator:");
Console.WriteLine("Last employee: " + company.listEmployees[^1].Name);
Console.WriteLine("Second-to-last employee: " + company.listEmployees[^2].Name);
Console.WriteLine("Third-to-last employee: " + company.listEmployees[^3].Name);
Console.WriteLine("\nChanging names using ^ operator:");
company.listEmployees[^1].Name = "Last Employee Updated";
company.listEmployees[^2].Name = "Second Last Updated";
Console.WriteLine("Updated last employee: " + company.listEmployees[^1].Name);
Console.WriteLine("Updated second-to-last: " + company.listEmployees[^2].Name);
}
}
The output of the above code is −
Using custom indexer: Employee with Id = 2: Bob Employee with Id = 5: Eve Employee with Id = 8: Henry Using index from end operator: Last employee: Henry Second-to-last employee: Grace Third-to-last employee: Frank Changing names using ^ operator: Updated last employee: Last Employee Updated Updated second-to-last: Second Last Updated
Comparison of Traditional vs New Index Methods
| Traditional Method | Index from End (^) Operator |
|---|---|
array[array.Length - 1] |
array[^1] |
list[list.Count - 2] |
list[^2] |
| More verbose and error-prone | Concise and readable |
| Requires knowledge of collection size | Works regardless of collection size |
Range Operator with Indexers
Example
using System;
class Program {
public static void Main() {
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("Original array: " + string.Join(", ", numbers));
// Get last 3 elements using range operator
var lastThree = numbers[^3..];
Console.WriteLine("Last 3 elements: " + string.Join(", ", lastThree));
// Get elements from index 2 to second-to-last
var middle = numbers[2..^1];
Console.WriteLine("Middle elements: " + string.Join(", ", middle));
// Get first 5 elements
var firstFive = numbers[..5];
Console.WriteLine("First 5 elements: " + string.Join(", ", firstFive));
}
}
The output of the above code is −
Original array: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Last 3 elements: 8, 9, 10 Middle elements: 3, 4, 5, 6, 7, 8, 9 First 5 elements: 1, 2, 3, 4, 5
Conclusion
C# 8.0's index from end operator (^) and range operator (..) provide a more intuitive and concise way to access elements from collections. Combined with custom indexers, they offer powerful capabilities for creating array-like access patterns in your classes while maintaining clean and readable code.
