
혹시 C#에서 컬렉션을 다루면서 이런 생각이 들지 않으셨나요?
"와, 이거 정말 편하다! 내가 직접 만든 클래스도 이렇게
배열이나 딕셔너리처럼 데이터를 다룰 수 있으면 얼마나 좋을까?"
놀랍게도, C#은 바로 그 기능도 제공합니다! 인덱서(Indexer)를 사용하면
우리가 만든 객체를 마치 배열처럼 인덱스로 접근할 수 있게 만들 수 있습니다.
인덱서(Indexer)는 클래스, 구조체, 인터페이스의 객체를 배열처럼
[ ]를 사용하여 인덱스로 접근할 수 있게 특별한 종류의 속성(Property)입니다.
인덱서는 메서드처럼 매개변수의 타입이나 개수를 다르게 하여 오버로딩할 수 있습니다.
우리가 도서관의 사서에게 "컴퓨터 과학 섹션의 세 번째 책 주세요!"
(library[ComputerScience, 3])라고 요청할 수 있습니다.
사서는 이 요청을 해석해서 실제 책장 어디에 있는 책을 가져다주죠.
우리는 책의 위치를 몰라도, '분류'와 '번호'라는 인덱스만으로 책에 접근할 수 있습니다.
인덱서는 이 사서처럼, 외부의 요청을 내부의 실제 데이터로 연결해 주는 역할을 합니다.
인덱서는 속성과 거의 똑같이 get과 set접근자를 가집니다.
가장 큰 차이점은, 속성은 '이름'을 가지지만 인덱서는
this키워드를 이름으로 사용하고 [ ]매개변수를 받는다는 점입니다.
| 구분 | 속성(Property) | 인덱서(Indexer) |
|---|---|---|
| 선언 | public int MyProperty { get; set; } | public int this[int index] { get; set; } |
| 호출 | obj.MyProperty = 10; | obj[0] = 10; |
학생들의 성적을 관리하는 클래스를 직접 만들어보며 인덱서를 구현해 봅시다.
내부적으로는 딕셔너리를 사용하여 데이터를 저장하겠지만,
외부에서는 이 사실을 숨기고 오직 이름(인덱스)만으로 점수에 접근하게 할 겁니다.
[코드]
using System;
using System.Linq; // ElementAt 메서드를 사용하려면 필요합니다.
using System.Collections.Generic; // 딕셔너리를 사용하려면 필요합니다.
public class Gradebook
{
// 1. 실제 데이터는 private Dictionary에 안전하게 보관 (내부 구현)
private Dictionary<string, int> _scores = new Dictionary<string, int>();
// 2. 인덱서(Indexer) 정의
public int this[string studentName]
{
// get 접근자: "grades[이름]"으로 점수를 읽으려 할 때 호출됨
get
{
// 해당 학생이 존재하지 않을 경우를 대비해 안전하게 접근
if (_scores.TryGetValue(studentName, out int score))
{
return score;
}
else
{
// 학생이 없으면 0점 또는 예외를 반환할 수 있음
Console.WriteLine($"{studentName} 학생의 정보가 없습니다.");
return 0;
}
}
// set 접근자: "grades[이름] = 점수"로 값을 할당할 때 호출됨
set
{
// 'value' 키워드는 할당하려는 값(점수)을 의미
if (value >= 0 && value <= 100)
{
// 학생 이름이 이미 있으면 점수 수정, 없으면 새로 추가
_scores[studentName] = value;
}
else
{
Console.WriteLine("유효하지 않은 점수입니다 (0 ~ 100).");
}
}
}
public int this[int index]
{
get
{
// 내부 Dictionary를 List로 변환하여 순서대로 접근
if (index >= 0 && index < _scores.Count)
{
// LINQ를 사용하여 N번째 요소의 값을 가져옴
return _scores.ElementAt(index).Value;
}
else
{
return -1; // 잘못된 인덱스
}
}
}
}
class Program
{
static void Main()
{
Gradebook myGrades = new Gradebook();
// 1. set 접근자 호출: 점수 할당
myGrades["홍길동"] = 95;
myGrades["김철수"] = 88;
myGrades["이영희"] = 101; // 유효성 검사에 걸림
// 2. get 접근자 호출: 점수 조회
Console.WriteLine($"홍길동의 점수: {myGrades["홍길동"]}");
Console.WriteLine($"김철수의 점수: {myGrades["김철수"]}");
Console.WriteLine($"이한결의 점수: {myGrades["이한결"]}"); // 존재하지 않는 학생
// 3. 정수 인덱서를 통한 점수 조회
Console.WriteLine($"첫 번째 학생의 점수: {myGrades[0]}");
}
}
[실행 결과]
유효하지 않은 점수입니다 (0 ~ 100).
홍길동의 점수: 95
김철수의 점수: 88
이한결 학생의 정보가 없습니다.
이한결의 점수: 0
첫 번째 학생의 점수: 95
인덱서는 C#의 사용성을 극적으로 향상하게 시키는 강력한 도구입니다.
| 인덱서의 장점 | 설명 |
|---|---|
| 직관적인 문법 | 객체를 배열이나 딕셔너리처럼 자연스럽게 사용할 수 있습니다. |
| 캡슐화 | 내부의 복잡한 데이터 구조를 숨기고, 외부에 일관된 접근 방식을 제공합니다. |
| 유연성 | int, string 등 다양한 타입의 인덱스를 사용할 수 있으며, 오버로딩도 가능합니다. |