개인 멤버로 두 개의 HashSet<String>
컬렉션이있는 클래스가 있습니다. 내 코드의 다른 클래스는 해당 HashSet을 반복하고 해당 내용을 읽을 수 있기를 원합니다. 나는 다른 클래스가 여전히 비슷한 것을 할 수 있기 때문에 표준 getter를 작성하고 싶지 않다. myClass.getHashSet().Clear();
HashSet 자체에 대한 참조를 노출하지 않고 내 HashSet의 요소를 반복에 노출시키는 다른 방법이 있습니까? for-each 루프와 호환되는 방식으로이 작업을 수행하고 싶습니다.(C#) 읽기 전용 개인 모음 멤버를 반복합니다.
답변
가 IEnumerable<T>
재산 노출 : 그래서 (상처 동안 성능) 안전을 위해
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet;
}
}
은 물론,이 코드의 사용자가 HashSet<T>
편집 요소가 IEnumerable<T>
캐스팅 할 수 있습니다, 당신은 할 수 수행
public IEnumerable<whatevertype> MyHashSet {
get {
return this.myHashSet.ToArray();
}
}
나 :
public IEnumerable<whatevertype> MyHashSet {
get {
foreach(var item in this.myHashSet) {
yield return item;
}
}
}
public IEnumerator<whatevertype> GetMyHashSetEnumerator() {
return this.myHashSet.GetEnumerator();
}
왜 'ToArray'옵션을 제시할까요? iterator 블록은 더 성능이 좋고 추가 메모리를 소비하지 않습니다. (컴파일러 생성 스텁 클래스의 설정 이외에). –
수율 접근 방식이 게으른 실행이고 더 많은 메모리를 사용해서는 안되기 때문에 가장 깨끗하다고 생각합니다. 나는 그것을 측정하지 않았다. –
흥미로운 질문 : 'yield return'이 ToArray()보다 빠르게 작동합니까? –
이 같은 방법/속성을 추가 실제 컨테이너를 노출하지 않도록 : 414,더 성능이 좋은 보호 방법,하지만 호출자에게 덜 편리한이 IEnumerator<T>
가 반환하는 것입니다
public IEnumerable EnumerateFirst()
{
foreach(var item in hashSet)
yield return item;
}
IEnumerable을 HashSet으로 다시 캐스팅하는 것을 막음으로써/진짜/불쾌한 호출자를 막을 수 있습니다. 그러나 IEnumerable을 강력하게 입력하는 것은 아닙니다. 그렇게 좋은 것은 아닙니다. –
+1. 다른 사람들은 'IEnumerable
...하지만 그것은 슬프게도, 슬프게도. – strager
만들기 Getter는 HashSet을 IEnumerable로 노출합니다.
private HashSet<string> _mine;
public IEnumerable<string> Yours
{
get { return _mine; }
}
제네릭 형식이 변경 가능한 경우
는, 그 여전히 수정할 수 있지만 아이템이 추가되지 또는 HashSet의에서 제거 할 수 있습니다. 이public IEnumerable<string> GetHashSetOneValues()
{
foreach (string value in hashSetOne)
yield return value;
}
이 방법은 다음 foreach 루프 내에서 호출 할 수 있습니다
:
foreach (string value in myObject.GetHashSetOneValues())
DoSomething(value);
예, 호출자가 'HashSet
좋아요, 그렇다면 어떤면에서도 안전 보장은 없습니다. _mine이 비공개 인스턴스 멤버 인 경우에도 리플렉션을 사용하여 얻을 수 있습니다. 소비자가 API에서 제공하는 계약을 위반하는 경우, 그렇게함으로써 결과를 받아 들여야합니다. IEnumerable
일반적으로 사용되는 것이 아니라 일반적으로 사용됩니다. 캐스팅과 반사 기반 개인 회원 액세스에는 큰 차이가 있습니다. –
당신은 또한이 같은 일련의를 제공 할 수있다 HashSet<T>
다시 캐스팅 할 수 없습니다
public IEnumerable<int> Values
{
get { return _values.Select(value => value);
}
목 는 .ToArray()
처럼 _values
을 두 번 반복하지 않지만 구현을 단일 깨끗한 선으로 유지합니다.
.NET 3.5를 사용한다고 가정하면 yield 코드를 직접 작성하는 대신 LINQ 메소드를 호출 할 수 있습니다. 예를 들어 :
public IEnumerable<string> HashSet
{
get { return privateMember.Select(x => x); }
}
또는
이public IEnumerable<string> HashSet
{
get { return privateMember.Skip(0); }
}
과 같이 사용할 수있는 다양한 LINQ 사업자가 있습니다 - 초기 이후로, Skip(0)
아마 가장 효율적으로 사용하여 "0 값을 생략"루프, 그것은이다 아마도 foreach
/yield return
루프가 다른 답변에 표시됩니다. Select
버전은 각 항목에 대해 no-op 투영 대리자를 호출합니다.이 차이가 중요 할 확률은 천문학적으로 작습니다. - 코드를 가장 명확하게 만드는 것은 무엇이든 함께하는 것이 좋습니다.
+1. 불필요한 람다 오버 헤드를 피하기 위해'Skip'을 사용할 것입니다. 굉장히 실용적이지는 않지만 실제로 여기서 당신을 얻지는 않습니다. –
+1; '건너 뛰기 (0)'는 좋은 생각입니다! – strager
이것은 파티에 너무 늦을 지 모르지만 오늘날 가장 쉬운 방법은 Linq를 사용하는 것입니다. 대신
public IEnumerable<string> GetValues()
{
foreach(var elem in list)
yield return elem;
}
을 쓰는 당신은 ESP,
public IEnumerable<string> GetValues() => list;
감사합니다, 모두를 쓸 수 있습니다. 가장 완벽한 답을 얻기위한 스트 레거, 그리고 내 OP를 정리 한 Jon Skeet. – DGH