누구든지 IEnumerable과 IEnumerator를 설명 할 수 있습니까?
예를 들어, foreach를 통해 언제 사용해야합니까? IEnumerable과 IEnumerator의 차이점은 무엇입니까? 왜 사용해야합니까?
답변
예를 들어, foreach를 통해 언제 사용해야합니까?
IEnumerable
“over”를 사용하지 않습니다 foreach
. 구현 IEnumerable
하면 사용이 foreach
가능해 집니다.
다음과 같은 코드를 작성할 때 :
foreach (Foo bar in baz)
{
...
}
기능적으로 다음과 같이 작성합니다.
IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
bar = (Foo)bat.Current
...
}
“기능적으로 동등한”이라는 말은 실제로 컴파일러가 코드를 변환하는 것입니다. 당신은 사용할 수 없습니다 foreach
에 baz
이 예에서 않는 baz
구현IEnumerable
.
IEnumerable
방법을 baz
구현하는 수단
IEnumerator GetEnumerator()
IEnumerator
이 메소드가 리턴 하는 오브젝트는 메소드를 구현해야합니다.
bool MoveNext()
과
Object Current()
첫 번째 메서드 IEnumerable
는 열거자를 만든 개체의 다음 개체로 진행하여 false
완료되면 반환하고 두 번째 메서드는 현재 개체를 반환합니다.
.Net에서 구현을 반복 할 수있는 모든 것 IEnumerable
. 자체 클래스를 작성 중이고 구현하는 클래스에서 아직 상속하지 않은 경우 구현하여 (및 새 메소드가 리턴 하는 열거 자 클래스를 작성하여) 클래스를 명령문 IEnumerable
에서 사용 가능하게 만들 수 있습니다 .foreach
IEnumerable
GetEnumerator
답변
IEnumerable 및 IEnumerator 인터페이스
기존 .NET 인터페이스를 구현하는 프로세스를 살펴보기 위해 먼저 IEnumerable 및 IEnumerator의 역할을 살펴 보겠습니다. C #은 모든 배열 유형의 내용을 반복 할 수있는 foreach라는 키워드를 지원합니다.
// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
Console.WriteLine(i);
}
배열 유형 만이 구성을 사용할 수있는 것처럼 보이지만 문제의 진실은 forEach 구성에 의해 평가 될 수있는 GetEnumerator ()라는 메소드를 지원하는 모든 유형입니다.
Garage 클래스가 있다고 가정하십시오.
// Garage contains a set of Car objects.
public class Garage
{
private Car[] carArray = new Car[4];
// Fill with some Car objects upon startup.
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
}
이상적으로는 데이터 값 배열과 마찬가지로 foreach 구문을 사용하여 Garage 객체의 하위 항목을 반복하는 것이 편리합니다.
// This seems reasonable ...
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
Garage carLot = new Garage();
// Hand over each car in the collection?
foreach (Car c in carLot)
{
Console.WriteLine("{0} is going {1} MPH",
c.PetName, c.CurrentSpeed);
}
Console.ReadLine();
}
}
안타깝게도 컴파일러는 Garage 클래스가 GetEnumerator ()라는 메서드를 구현하지 않음을 알려줍니다. 이 메서드는 System.Collections 네임 스페이스 내에 숨겨져있는 IEnumerable 인터페이스로 공식화됩니다. 이 동작을 지원하는 클래스 또는 구조는 포함 된 하위 항목을 호출자 (이 예제에서는 foreach 키워드 자체)에 노출 할 수 있음을 알립니다. 이 표준 .NET 인터페이스의 정의는 다음과 같습니다.
// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
보다시피 GetEnumerator () 메서드는 System.Collections.IEnumerator라는 또 다른 인터페이스에 대한 참조를 반환합니다. 이 인터페이스는 호출자가 IEnumerable 호환 컨테이너에 포함 된 내부 객체를 통과 할 수있는 인프라를 제공합니다.
// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
이러한 인터페이스를 지원하도록 차고 유형을 업데이트하려는 경우 시간이 오래 걸리고 각 방법을 수동으로 구현할 수 있습니다. GetEnumerator (), MoveNext (), Current 및 Reset ()의 사용자 정의 버전을 자유롭게 제공 할 수 있지만 더 간단한 방법이 있습니다. System.Array 유형 (및 다른 많은 컬렉션 클래스)은 이미 IEnumerable 및 IEnumerator를 구현하므로 다음과 같이 간단히 요청을 System.Array에 위임 할 수 있습니다.
using System.Collections;
...
public class Garage : IEnumerable
{
// System.Array already implements IEnumerator!
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("FeeFee", 200);
carArray[1] = new Car("Clunker", 90);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
}
차고 유형을 업데이트 한 후 C # foreach 구문 내에서 해당 유형을 안전하게 사용할 수 있습니다. 또한 GetEnumerator () 메서드가 공개적으로 정의 된 경우 개체 사용자는 IEnumerator 형식과 상호 작용할 수도 있습니다.
// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);
그러나 개체 수준에서 IEnumerable의 기능을 숨기려면 명시 적 인터페이스 구현을 사용하십시오.
IEnumerator IEnumerable.GetEnumerator()
{
// Return the array object's IEnumerator.
return carArray.GetEnumerator();
}
그렇게하면 일반 객체 사용자는 Garage의 GetEnumerator () 메소드를 찾지 못하지만 foreach 구문은 필요한 경우 백그라운드에서 인터페이스를 가져옵니다.
답변
IEnumerable을 구현하면 클래스에서 IEnumerator 객체를 반환합니다.
public class People : IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
// return a PeopleEnumerator
}
}
IEnumerator를 구현한다는 것은 클래스가 반복을위한 메소드와 속성을 반환한다는 것을 의미합니다.
public class PeopleEnumerator : IEnumerator
{
public void Reset()...
public bool MoveNext()...
public object Current...
}
어쨌든 차이점입니다.
답변
유추 + 코드 연습을 통한 설명
먼저 코드없이 설명을 한 다음 나중에 추가하겠습니다.
항공사를 운영하고 있다고 가정 해 봅시다. 그리고 각 비행기에서 비행기에 탑승하는 승객에 대한 정보를 알고 싶습니다. 기본적으로 비행기를 “이동”할 수 있기를 원합니다. 다시 말해, 승객은 앞 좌석에서 출발 한 다음 비행기 뒤쪽으로 나아갈 수 있기를 원하며 승객에게 정보를 요청합니다. 승객의 위치, 위치 등 이면 :
- 셀 수있는
- 카운터가 있으면
왜 이러한 요구 사항이 있습니까? 인터페이스에 필요한 것이기 때문입니다.
이것이 정보 과부하 인 경우, 비행기에서 각 승객에게 처음부터 시작하여 마지막까지 몇 가지 질문을 할 수 있기를 원한다는 것만 알면됩니다.
셀 수있는 것은 무엇을 의미합니까?
항공사가 “가산 성”인 경우, 비행기에 승무원이 있어야하며, 유일한 직원은 계산해야하며,이 승무원은 매우 구체적인 방식으로 계산해야합니다.
- 카운터 / 비행 승무원은 첫 승객보다 먼저 출발해야합니다 (안전을 시연하는 모든 사람 앞에서, 구명 조끼 착용 방법 등).
- 그 / 그녀 (즉, 승무원)는 통로에서 첫 좌석으로 “다음으로 이동”해야합니다.
- 그 후 그녀는 (i) 좌석에있는 사람, (ii) 통로에서 현재 위치를 기록해야합니다.
계산 절차
항공사의 선장은 모든 승객에 대해 조사 또는 계산 시점에 대한 보고서를 원합니다. 따라서 첫 번째 좌석에있는 사람에게 말한 후 승무원 / 카운터는 선장에게보고하고, 보고서가 제공되면 카운터는 통로에서 자신의 정확한 위치를 기억하고 자신이 떠난 곳에서 계속 카운팅합니다. 떨어져서.
이런 식으로 선장은 항상 현재 조사중인 사람에 대한 정보를 가질 수 있습니다. 그렇게하면,이 개인이 맨체스터 시티를 좋아한다는 것을 알게되면, 그 승객에게 우선 치료 등을 줄 수 있습니다.
- 비행기가 끝날 때까지 카운터는 계속 진행합니다.
이것을 IEnumerables와 묶어 봅시다
-
열거 가능한 것은 비행기에 승객을 모은 것입니다. 민간 항공법-기본적으로 모든 IEnumerables가 따라야하는 규칙입니다. 항공사 승무원이 Passeger 정보를 사용하여 선장으로 갈 때마다 기본적으로 승객을 선장에게 ‘수속’합니다. 기장은 기본적으로 승객을 비행기에 다시 배치하는 것을 제외하고는 승객과 함께 원하는 모든 것을 할 수 있습니다. 이 경우 맨체스터 시티를 따를 경우 우선 치료를받습니다 (웃음).
foreach (Passenger passenger in Plane) // the airline hostess is now at the front of the plane // and slowly making her way towards the back // when she get to a particular passenger she gets some information // about the passenger and then immediately heads to the cabin // to let the captain decide what to do with it { // <---------- Note the curly bracket that is here. // we are now cockpit of the plane with the captain. // the captain wants to give the passenger free // champaign if they support manchester city if (passenger.supports_mancestercity()) { passenger.getFreeChampaign(); } else { // you get nothing! GOOD DAY SIR! } } // <---- Note the curly bracket that is here! the hostess has delivered the information to the captain and goes to the next person on the plane (if she has not reached the end of the plane)
요약
즉, 카운터가 있으면 무언가를 계산할 수 있습니다 . 그리고 카운터는 (기본적으로) : (i) 그 장소를 기억하고 ( state ), (ii) 다음 으로 움직일 수 있고 , (iii) 그가 다루고 있는 현재 사람 에 대해 알고 있어야합니다 .
열거 형은 “가산 성”에 대한 멋진 단어입니다. 즉, 열거 가능하면 ‘열거'(즉, 계산) 할 수 있습니다.
답변
IEnumerable 은 GetEnumerator를 구현합니다. 호출되면 해당 메소드는 IEnumerator 를 리턴합니다. MoveNext, Reset 및 Current를 구현 를 .
따라서 클래스에서 IEnumerable을 구현하면 메서드 (GetEnumerator)를 호출하고 foreach와 같은 루프에서 사용할 수있는 새 개체 (IEnumerator)를 반환 할 수 있습니다.
답변
IEnumerable을 구현하면 목록에 대한 IEnumerator를 얻을 수 있습니다.
IEnumerator에서는 yield 키워드를 사용하여 각 스타일을 목록의 항목에 순차적으로 액세스 할 수 있습니다.
foreach를 구현하기 전에 (예 : Java 1.4) 목록을 반복하는 방법은 목록에서 열거자를 가져온 다음 다음에 반환 된 값만큼 목록에서 “다음”항목을 요청하는 것입니다. 항목이 null이 아닙니다. foreach는 단순히 lock ()이이면에서 Monitor 클래스를 구현하는 것과 같은 방식으로 언어 기능으로 암시 적으로 수행합니다.
foreach는 IEnumerable을 구현하기 때문에 목록에서 작동합니다.
답변
- IEnumerable을 구현하는 개체를 사용하면 다른 사람이 각 항목을 열거 자로 열거 할 수 있습니다. .
- IEnumerator를 구현하는 객체 는 반복을 수행하는 것입니다. 열거 가능한 객체를 반복합니다.
열거 가능한 객체를 목록, 스택, 트리로 생각하십시오.