foreach 루프를 사용할 수 있는 일반화(generic) 클래스는 IEnumerable<T> 인터페이스를 구현한 클래스입니다. 이 인터페이스를 구현하면 해당 클래스의 인스턴스를 foreach 루프에서 반복할 수 있게 됩니다.
IEnumerable<T> 인터페이스는 C#에서 컬렉션을 반복하는 데 사용되는 기본적인 인터페이스 중 하나입니다. 이 인터페이스는 다음과 같이 정의되어 있습니다:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
여기서 중요한 것은 GetEnumerator 메서드입니다. 이 메서드는 컬렉션에서 IEnumerator<T> 인터페이스를 반환합니다. IEnumerator<T> 인터페이스를 구현한 클래스는 컬렉션을 반복하는 데 필요한 메서드 및 속성을 제공합니다.
IEnumerator<T> 인터페이스는 다음과 같이 정의되어 있습니다:
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
T Current { get; }
bool MoveNext();
void Reset();
}
IEnumerable<T> 인터페이스를 구현하는 클래스는 GetEnumerator 메서드를 구현하고, 이 메서드에서 해당 클래스의 반복자(enumerator)를 반환해야 합니다. 반복자는 IEnumerator<T> 인터페이스를 구현하며, Current 속성을 통해 현재 요소에 접근하고, MoveNext 메서드를 호출하여 다음 요소로 이동합니다.
일반적으로 foreach 루프를 사용하려면 컬렉션 클래스가 IEnumerable<T> 인터페이스를 구현하고 있어야 합니다. 이를 통해 foreach 루프에서 컬렉션의 각 요소를 순회할 수 있게 됩니다.
IEnumerable<T> 인터페이스를 구현한 컬렉션들은 C#에서 반복 가능한 컬렉션을 나타냅니다. 이 인터페이스를 구현하면 컬렉션의 요소를 순회할 수 있는 기능을 제공합니다. 아래는 몇 가지 IEnumerable<T> 인터페이스를 구현한 일반적인 컬렉션의 몇 가지 예제입니다:
List<T>: List<T>는 가장 많이 사용되는 IEnumerable<T>를 구현한 컬렉션 중 하나입니다. 리스트에 요소를 추가하고 순회하는 데 사용할 수 있습니다.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Array: 배열도 IEnumerable<T>를 구현합니다. 배열은 고정된 크기를 가지며 요소를 순회할 수 있습니다.
int[] array = new int[] { 1, 2, 3, 4, 5 };
Dictionary<TKey, TValue>: 사전은 IEnumerable<KeyValuePair<TKey, TValue>>를 구현합니다. foreach를 사용하여 키-값 쌍을 순회할 수 있습니다.
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("One", 1);
dictionary.Add("Two", 2);
dictionary.Add("Three", 3);
HashSet<T>: HashSet<T>는 고유한 값만 저장하는 집합을 나타내며 IEnumerable<T>를 구현합니다.
HashSet<string> set = new HashSet<string> { "apple", "banana", "cherry" };
LinkedList<T>: LinkedList<T>는 노드 기반 연결 리스트를 나타내며 IEnumerable<T>를 구현합니다.
LinkedList<int> linkedList = new LinkedList<int>();
linkedList.AddLast(1);
linkedList.AddLast(2);
linkedList.AddLast(3);
이러한 컬렉션들은 IEnumerable<T>를 구현하여 foreach 루프를 사용하여 요소를 순회할 수 있도록 합니다. 이것은 C#에서 컬렉션을 다루는 일반적인 방법 중 하나입니다.
// 1. IEnumerable<Person>을 상속받는 방식
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void SayHello()
{
Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");
}
}
public class PeopleCollection : IEnumerable<Person>
{
private List<Person> people = new List<Person>();
public void Add(Person person)
{
people.Add(person);
}
public void Edit(string name, int age)
{
Person person = people.FirstOrDefault(p => p.Name == name);
if (person != null)
{
person.Age = age;
}
}
public void Remove(string name)
{
Person personToRemove = people.FirstOrDefault(p => p.Name == name);
if (personToRemove != null)
{
people.Remove(personToRemove);
}
}
public IEnumerator<Person> GetEnumerator()
{
return people.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static void Main()
{
PeopleCollection peopleCollection = new PeopleCollection();
Person person1 = new Person { Name = "Alice", Age = 30 };
Person person2 = new Person { Name = "Bob", Age = 25 };
Person person3 = new Person { Name = "Charlie", Age = 35 };
peopleCollection.Add(person1);
peopleCollection.Add(person2);
peopleCollection.Add(person3);
foreach (var person in peopleCollection)
{
person.SayHello();
}
Console.WriteLine("\nAfter editing Alice's age:");
peopleCollection.Edit("Alice", 31);
foreach (var person in peopleCollection)
{
person.SayHello();
}
Console.WriteLine("\nAfter removing Bob:");
peopleCollection.Remove("Bob");
foreach (var person in peopleCollection)
{
person.SayHello();
}
}
}
Hello, my name is Alice and I am 30 years old.
Hello, my name is Bob and I am 25 years old.
Hello, my name is Charlie and I am 35 years old.
After editing Alice's age:
Hello, my name is Alice and I am 31 years old.
Hello, my name is Bob and I am 25 years old.
Hello, my name is Charlie and I am 35 years old.
After removing Bob:
Hello, my name is Alice and I am 31 years old.
Hello, my name is Charlie and I am 35 years old.
// 2, List<Person> 상속받는 방식.
using System;
using System.Collections.Generic;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void SayHello()
{
Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");
}
}
public class PeopleCollection : List<Person>
{
public void AddPerson(string name, int age)
{
Add(new Person { Name = name, Age = age });
}
public void EditPerson(string name, int age)
{
foreach (var person in this)
{
if (person.Name == name)
{
person.Age = age;
return;
}
}
}
public void RemovePerson(string name)
{
RemoveAll(person => person.Name == name);
}
public void DisplayPeople()
{
Console.WriteLine("Current People:");
foreach (var person in this)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
}
class Program
{
static void Main()
{
PeopleCollection peopleCollection = new PeopleCollection();
peopleCollection.AddPerson("Alice", 30);
peopleCollection.AddPerson("Bob", 25);
Console.WriteLine("Initial List:");
peopleCollection.DisplayPeople();
Console.WriteLine("\nAfter Editing:");
peopleCollection.EditPerson("Alice", 35);
peopleCollection.DisplayPeople();
Console.WriteLine("\nAfter Removing:");
peopleCollection.RemovePerson("Alice");
peopleCollection.DisplayPeople();
Console.WriteLine("\nAfter Calling SayHello:");
foreach (var person in peopleCollection)
{
person.SayHello();
}
}
}
Initial List:
Current People:
Name: Alice, Age: 30
Name: Bob, Age: 25
After Editing:
Current People:
Name: Alice, Age: 35
Name: Bob, Age: 25
After Removing:
Current People:
Name: Bob, Age: 25
After Calling SayHello:
Hello, my name is Bob and I am 25 years old.
//PeopleCollection을 List<Person>을 상속하고 Person 객체를 List에 추가하여 구현할 수 있습니다. 다음은 이러한 방식으로 구현한 예제입니다:
using System;
using System.Collections.Generic;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public void SayHello()
{
Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");
}
}
public class PeopleCollection : List<Person>
{
public void AddPerson(string name, int age)
{
Person person = new Person { Name = name, Age = age };
this.Add(person);
}
public void EditPersonAge(string name, int newAge)
{
Person person = this.Find(p => p.Name == name);
if (person != null)
{
person.Age = newAge;
}
}
public void RemovePerson(string name)
{
Person person = this.Find(p => p.Name == name);
if (person != null)
{
this.Remove(person);
}
}
}
class Program
{
static void Main()
{
PeopleCollection people = new PeopleCollection();
people.AddPerson("Alice", 30);
people.AddPerson("Bob", 25);
people.AddPerson("Charlie", 35);
foreach (var person in people)
{
person.SayHello();
}
people.EditPersonAge("Alice", 31);
Console.WriteLine("\nAfter editing Alice's age:");
foreach (var person in people)
{
person.SayHello();
}
people.RemovePerson("Bob");
Console.WriteLine("\nAfter removing Bob:");
foreach (var person in people)
{
person.SayHello();
}
}
}
Hello, my name is Alice and I am 30 years old.
Hello, my name is Bob and I am 25 years old.
Hello, my name is Charlie and I am 35 years old.
After editing Alice's age:
Hello, my name is Alice and I am 31 years old.
Hello, my name is Bob and I am 25 years old.
Hello, my name is Charlie and I am 35 years old.
After removing Bob:
Hello, my name is Alice and I am 31 years old.
Hello, my name is Charlie and I am 35 years old.
List<Person>을 상속받는 방식과 IEnumerable<Person> 인터페이스를 구현하는 방식은 각각의 장단점이 있습니다. 어떤 방식을 선택할지는 상황과 요구사항에 따라 다를 수 있습니다.
List<Person> 상속 방식:
장점:
기본적인 리스트 동작을 모두 상속받으므로 리스트를 사용하는 다양한 메서드와 기능을 활용할 수 있습니다. 예를 들어 Add, Remove, Clear, Sort 등의 메서드를 쉽게 사용할 수 있습니다.
코드가 간결하며 직관적입니다.
단점:
List<Person> 클래스를 직접 상속받기 때문에 다중 상속이 필요한 경우에는 제한이 있을 수 있습니다.
클래스의 구조를 변경하기 위해 해당 클래스의 소스 코드에 직접 접근해야 할 수 있으므로 라이브러리 클래스일 경우 수정이 어려울 수 있습니다.
IEnumerable<Person> 인터페이스 구현 방식:
장점:
인터페이스를 구현함으로써 클래스가 다른 클래스와 호환성을 가질 수 있습니다. 이 클래스를 다른 컬렉션과 함께 사용할 때 더 유연성을 제공합니다.
클래스의 동작을 더 정확하게 제어할 수 있으며, 필요한 메서드와 속성만 노출시킬 수 있습니다.
단점:
컬렉션의 기본 동작을 사용하기 위해 별도의 구현이 필요하며, 코드가 상대적으로 더 복잡해질 수 있습니다.
필요한 경우 컬렉션 관련 메서드와 동작을 직접 구현해야 하므로 시간과 노력이 더 필요합니다.
따라서 어떤 방식을 선택할지는 프로젝트의 특정 요구사항과 목표에 따라 다릅니다. 간단한 리스트를 다루는 경우에는 List<Person>을 상속받는 방식이 편리할 수 있지만, 라이브러리나 클래스의 재사용성을 고려하거나 더 정교한 컨트롤이 필요한 경우에는 IEnumerable<Person> 인터페이스 구현 방식이 유용할 수 있습니다.
LinkedList<T> (0) | 2023.09.05 |
---|---|
HashSet<T> (0) | 2023.09.05 |
Dictionary (0) | 2023.09.05 |
Stack (0) | 2023.09.05 |
Queue (0) | 2023.09.05 |