다음과 같이 비 제네릭 IEnumerable을 구현하는 방법을 알고 있습니다.
using System;
using System.Collections;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
MyObjects myObjects = new MyObjects();
myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };
foreach (MyObject x in myObjects)
{
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
Console.ReadLine();
}
}
class MyObject
{
public string Foo { get; set; }
public int Bar { get; set; }
}
class MyObjects : IEnumerable
{
ArrayList mylist = new ArrayList();
public MyObject this[int index]
{
get { return (MyObject)mylist[index]; }
set { mylist.Insert(index, value); }
}
IEnumerator IEnumerable.GetEnumerator()
{
return mylist.GetEnumerator();
}
}
}
그러나 IEnumerable에는 제네릭 버전이 IEnumerable<T>
있지만 구현 방법을 알 수 없습니다.
using System.Collections.Generic;
using 지시문에 추가 한 다음 변경하면 :
class MyObjects : IEnumerable
에:
class MyObjects : IEnumerable<MyObject>
그런 다음을 마우스 오른쪽 버튼으로 클릭 하고을 IEnumerable<MyObject>
선택 Implement Interface => Implement Interface
하면 Visual Studio가 다음 코드 블록을 유용하게 추가합니다.
IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
throw new NotImplementedException();
}
GetEnumerator();
메서드 에서 제네릭이 아닌 IEnumerable 개체를 반환하는 것은 이번에는 작동하지 않으므로 여기에 무엇을 입력해야합니까? CLI는 이제 일반이 아닌 구현을 무시하고 foreach 루프 동안 내 배열을 열거하려고 할 때 일반 버전으로 곧장 향합니다.
답변
당신과 같은 일반적인 수집, 사용하기로 선택한 경우 List<MyObject>
대신을 ArrayList
, 당신은이 것을 찾을 수 있습니다 List<MyObject>
당신이 사용할 수있는 모두 일반 및 제네릭이 아닌 열거를 제공합니다.
using System.Collections;
class MyObjects : IEnumerable<MyObject>
{
List<MyObject> mylist = new List<MyObject>();
public MyObject this[int index]
{
get { return mylist[index]; }
set { mylist.Insert(index, value); }
}
public IEnumerator<MyObject> GetEnumerator()
{
return mylist.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
답변
당신은 아마도 (당신이 보여준) 명시적인 구현을 원하지 않을 것입니다 IEnumerable<T>
.
일반적인 패턴은 다음을 명시 적으로 구현할 때 IEnumerable<T>
‘ 를 사용 GetEnumerator
하는 것입니다 IEnumerable
.
class FooCollection : IEnumerable<Foo>, IEnumerable
{
SomeCollection<Foo> foos;
// Explicit for IEnumerable because weakly typed collections are Bad
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
// uses the strongly typed IEnumerable<T> implementation
return this.GetEnumerator();
}
// Normal implementation for IEnumerable<T>
IEnumerator<Foo> GetEnumerator()
{
foreach (Foo foo in this.foos)
{
yield return foo;
//nb: if SomeCollection is not strongly-typed use a cast:
// yield return (Foo)foo;
// Or better yet, switch to an internal collection which is
// strongly-typed. Such as List<T> or T[], your choice.
}
// or, as pointed out: return this.foos.GetEnumerator();
}
}
답변
수동으로하는 이유는 무엇입니까? yield return
반복자를 처리하는 전체 프로세스를 자동화합니다. (저는 제 블로그 에도 썼습니다. 컴파일러 생성 코드를 포함하여 .)
정말로 직접하고 싶다면 제네릭 열거 자도 반환해야합니다. 일반이 아니기 때문에 ArrayList
더 이상 사용할 수 없습니다 . List<MyObject>
대신 a로 변경하십시오 . 물론 MyObject
컬렉션 에 유형 (또는 파생 유형)의 개체 만 있다고 가정합니다 .
답변
제네릭으로 작업하는 경우 ArrayList 대신 List를 사용하십시오. List에는 필요한 GetEnumerator 메서드가 있습니다.
List<MyObject> myList = new List<MyObject>();
답변
mylist를으로 만드는 List<MyObject>
것은 하나의 옵션입니다.
답변
에 IEnumerable<T>
의해 구현 된 allready System.Collections
또 다른 접근 방식은 MyObjects
클래스를 System.Collections
기본 클래스 ( documentation ) 로 파생하는 것입니다 .
System.Collections : 제네릭 컬렉션에 대한 기본 클래스를 제공합니다.
우리는 나중에 우리 자신의 된 구현 가상 재정의 할 수 있습니다 System.Collections
사용자 정의 동작을 제공하는 방법을 (만 해당 ClearItems
, InsertItem
, RemoveItem
,와 SetItem
함께 Equals
, GetHashCode
및 ToString
에서 Object
). 달리List<T>
쉽게 확장 할 수 있도록 설계되지 않은 다릅니다.
예:
public class FooCollection : System.Collections<Foo>
{
//...
protected override void InsertItem(int index, Foo newItem)
{
base.InsertItem(index, newItem);
Console.Write("An item was successfully inserted to MyCollection!");
}
}
public static void Main()
{
FooCollection fooCollection = new FooCollection();
fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}
collection
드물게 발생하는 맞춤형 수집 행동이 필요한 경우에만 운전을 권장합니다. 사용법을 참조하십시오 .