C#에는 Index를 다룰 수 있는 Index 클래스가 존재하는데 다른 언어와 같이 인덱스기반 접근 기능에 뒤에서 탐색하는 방향의 개념을 추가한 개념이라고 보면 된다.
아래 코드를 보면 ^1과 같이 인덱스 숫자 앞에 ^가 붙은 것이 Index 객체이고 ^가 붙은 것은 '뒤에서부터 인덱스 참조를 한다.'는 것을 의미한다.
^가 붙은 인덱싱은 0부터 시작하는 것이 아니라 1부터 시작하기 때문에 ^1이 제일 뒤에 있는 것을 가져온다.
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
int n1 = arr[2];
int n2 = arr[^1];
Console.WriteLine($"{n1}, {n2}"); // 3, 11
new로 생성 // 1. new 사용
Index i1 = new Index();
Index i2 = new Index(3, true);
// 2. new 사용
Index i3 = Index.FromStart(3);
Index i4 = Index.FromEnd(3);
// 3. new 사용
Index i5 = 3;
Index i6 = ^3;
Index 객체에는 현재 위치정보나 방향정보에 대한 프로퍼티가 정의되어 있는데 Value가 현재 위치한 인덱스 정보이고 IsFromEnd가 방향 정보를 나타낸다.

class Csequence
{
private int[] arr = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
public int this[int idx] { get { return arr[idx]; } }
}
public static void Main(string[] args)
{
Csequence csequence = new Csequence();
Console.WriteLine(csequence[1]); // Ok!
Console.WriteLine(csequence[^1]); // Error!
}
^1은 int가 아니라 Index 객체이기 때문에 Index 객체를 받는 새로운 Indexer를 정의해야한다. 아래 코드와 같이 새로운 Indexer를 정의하면 에러가 발생하지 않고 ^1과 같은 Index 객체 접근이 가능하다.
class Csequence
{
private int[] arr = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
public int this[int idx] { get { return arr[idx]; } }
public int this[Index idx] { get { return arr[idx]; } }
}
Index 객체 기반 Indexer의 동작 순서는 다음과 같다.
즉 위의 순서에 따르면 Index 객체 Indexer가 정의되어 있지 않아도 Length나 Count같은 길이를 알 수 있는 방법이 존재한다면 컴파일러가 자동으로 ^1과 같은 Index를 길이로 변환시켜 준다는 것이다.
위의 예제에서 아래와 같이 Length 프로퍼티를 추가해준다면, FromEnd 접근도 가능하게 될 것이다.
class Csequence
{
private int[] arr = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
public int this[int idx] { get { return arr[idx]; } }
public int Length { get { return arr.Length; } }
}
public static void Main(string[] args)
{
Csequence csequence = new Csequence();
Console.WriteLine(csequence[1]); // Ok!
Console.WriteLine(csequence[^1]); // Ok!
}