C#은 C ++ 반복자와 같은 열거 자의 종류 간의 구별로부터 이익을 얻을 수 있습니까?

StackOverflow https://stackoverflow.com/questions/1634934

  •  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(), 처음에 그것을 추가하는 것은 실수라는 것이 널리 받아 들여졌습니다. 그것이 효과가 있고 올바르게 구현 된 경우, 당신은 당신의 열거자가 반복자를 전달하는 것과 유사하다고 말할 수 있지만, 일반적으로 실수로 무시하는 것이 가장 좋습니다. 그런 다음 모든 열거자는 입력 반복자 와만 유사합니다.

안타깝게도.

다른 팁

Reset 큰 실수였습니다. 나는 shenanigans를 불렀다 Reset. 제 생각에 .NET 유형 시스템에서 "전방 반복자"와 "입력 반복자"사이의 구별을 반영하는 올바른 방법은 IEnumerable<T> 그리고 IEnumerator<T>.

또한보십시오 이 답변, Microsoft의 Eric Lippert (비공식적 인 capactiy에서, 의심 할 여지없이, 내 요점은 그가 디자인 실수라고 주장하는 것보다 더 많은 자격 증명을 가진 사람이라는 것입니다)는 비슷한 의견을 제시합니다. 또한 참조하십시오 그의 멋진 블로그.

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> 프로그래머가 무작위 액세스를 원하는 경우.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top