C#은 C ++ 반복자와 같은 열거 자의 종류 간의 구별로부터 이익을 얻을 수 있습니까?
-
06-07-2019 - |
문제
나는 생각하고있다 IEnumerator.Reset()
방법. MSDN 문서에서 COM Interop에 대해서만 읽었습니다. C ++ 프로그래머로서 그것은 나에게 IEnumerator
지원합니다 Reset
내가 부르는 것입니다 전방 반복자, IEnumerator
지원하지 않습니다 Reset
정말입니다 입력 반복자.
그래서 제 질문 중 하나는이 이해가 정확합니까?
내 질문의 두 번째 부분은 입력 반복자와 전방 반복자 (또는 선호하는 경우 "열거 자") 사이에 차이가있는 경우 C#에 어떤 이점이 있습니까? 이것에서 발견 된 것과 같이 프로그래머들 사이의 혼란을 제거하는 데 도움이되지 않습니까? 복제 반복자에 대한 질문?
편집 : 전방 및 입력 반복자에 대한 설명. 입력 반복자는 컬렉션의 멤버 (또는 생성기 함수 또는 입력 스트림)를 한 번만 열거 할 수 있음을 보장합니다. 이것이 바로 Ienumerator가 C#에서 작동하는 방식입니다. 두 번째로 열거 할 수 있는지 여부는 Reset
지원됩니다. 전방 반복자는 이러한 제한이 없습니다. 원하는만큼 자주 회원을 열거 할 수 있습니다.
일부 C# 프로그래머는 이유를 과소 평가하지 않습니다 IEnumerator
멀티 패스 알고리즘에 안정적으로 사용할 수 없습니다. 다음 경우를 고려하십시오.
void PrintContents(IEnumerator<int> xs)
{
while (iter.MoveNext())
Console.WriteLine(iter.Current);
iter.Reset();
while (iter.MoveNext())
Console.WriteLine(iter.Current);
}
우리가 전화하면 PrintContents
이러한 맥락에서 문제는 없습니다.
List<int> ys = new List<int>() { 1, 2, 3 }
PrintContents(ys.GetEnumerator());
그러나 다음을보십시오.
IEnumerable<int> GenerateInts() {
System.Random rnd = new System.Random();
for (int i=0; i < 10; ++i)
yield return Rnd.Next();
}
PrintContents(GenerateInts());
만약 IEnumerator
지원 Reset
, 다시 말해서 멀티 패스 알고리즘을 지원 한 다음 컬렉션을 반복 할 때마다 다를 수 있습니다. 놀라운 행동이기 때문에 이것은 바람직하지 않을 것입니다. 이 예는 약간 위조되었지만 실제 세계에서 발생합니다 (예 : 파일 스트림에서 읽는 것).
해결책
흥미로운 질문. 내 테이크는 물론 C#입니다 혜택. 그러나 추가하기는 쉽지 않습니다.
훨씬 더 유연한 유형 시스템으로 인해 C ++에 차이가 있습니다. C#에는 전방 반복을 나타내는 데 필요한 객체를 복제하는 강력한 일반적인 방법이 없습니다 (멀티 패스 반복을 지원하기 위해). 물론 이것이 정말로 유용하기 위해서는 양방향 및 임의 액세스 반복자/열거자를 지원해야합니다. 그리고 모두 원활하게 작동하기 위해서는 C ++ 템플릿과 같이 어떤 형태의 오리 타자가 필요합니다.
궁극적으로 두 개념의 범위는 다릅니다.
C ++에서 반복자는 다양한 값에 대해 알아야 할 모든 것을 나타내야합니다. 한 쌍의 반복자가 주어지면 나는 그렇지 않습니다 필요 원래 컨테이너. 나는 정렬 할 수 있고, 검색 할 수 있고, 내가 좋아하는만큼 요소를 조작하고 복사 할 수 있습니다. 원래 컨테이너가 그림에서 나왔습니다.
C#에서 열거자는 그다지 많은 일을하지 않습니다. 궁극적으로 그들은 단지 선형 방식으로 시퀀스를 통과 할 수 있도록 설계되었습니다.
에 관해서 Reset()
, 처음에 그것을 추가하는 것은 실수라는 것이 널리 받아 들여졌습니다. 그것이 효과가 있고 올바르게 구현 된 경우, 당신은 당신의 열거자가 반복자를 전달하는 것과 유사하다고 말할 수 있지만, 일반적으로 실수로 무시하는 것이 가장 좋습니다. 그런 다음 모든 열거자는 입력 반복자 와만 유사합니다.
안타깝게도.
다른 팁
C# 관점에서 오는 :
당신은 거의 사용하지 않습니다 IEnumerator
곧장. 보통 당신은 a foreach
a IEnumerable
.
IEnumerable _myCollection;
...
foreach (var item in _myCollection) { /* Do something */ }
당신은 지나치지 않습니다 IEnumerator
어느 하나. 반복이 필요한 컬렉션을 통과하려면 통과합니다. IEnumerable
. 부터 IEnumerable
반환하는 단일 함수가 있습니다 IEnumerator
, 컬렉션을 여러 번 반복하는 데 사용할 수 있습니다 (다중 패스).
필요하지 않습니다 Reset()
기능 IEnumerator
다시 시작하고 싶다면 오래된 것을 버리고 (수집 된 쓰레기) 새로운 것을 얻으십시오.
.NET 프레임 워크는 IEnumerator<T>
그것이 지원할 수있는 능력과 그것이 어떤 약속을 할 수 있는지에 대해. 이러한 기능도 도움이 될 것입니다 IEnumerable<T>
, 그러나 열거 자의 질문을 할 수 있으면 래퍼로부터 열거자를받을 수있는 코드가 허용됩니다. ReadOnlyCollection
래퍼를 참여시키지 않고도 개선 방법으로 기본 컬렉션을 사용합니다.
전체적으로 열거 될 수 있고 너무 크지 않은 컬렉션에 대한 열거자를 주어 주면 IEnumerable<T>
이는 항상 전체 내용을 배열에 읽고 열거자를 처리 및 폐기하여 동일한 항목 (특히 열거 자에 남아있는 항목 세트)을 생성합니다. 버려진 열거 자), 배열을 a ReadOnlyCollection<T>
, 그리고 그것을 반환합니다. 이러한 접근 방식은 위의 기준을 충족하는 모든 종류의 열거 가능한 컬렉션과 함께 작동하지만 대부분의 사람들에게는 끔찍하게 비효율적입니다. 열거 자에게 불변의 내용물을 산출하도록 요청하는 수단이 있습니다. IEnumerable<T>
많은 종류의 열거자가 지시 된 동작을 훨씬 더 효율적으로 수행 할 수 있습니다.
나는 그렇게 생각하지 않습니다. 나는 전화 할 것이다 IEnumerable
전방 반복자 및 입력 반복기. 뒤로 가거나 기본 컬렉션을 수정할 수 없습니다. 추가 foreach
키워드, 반복자는 대부분의 시간이 거의없는 것입니다.
의견 : 입력 반복기의 차이 (각각을 얻으십시오) 대 출력 반복자 (각자에게 뭔가를하십시오)는 프레임 워크에 추가를 정당화하기에는 너무 사소합니다. 또한 출력 반복기를 수행하려면 대의원을 반복자에게 전달해야합니다. 입력 반복자는 C# 프로그래머에게 더 자연스럽게 보입니다.
또한 있습니다 IList<T>
프로그래머가 무작위 액세스를 원하는 경우.