IEnumberable의 다중 열거 가능성에 대한 경고 처리
내 코드에서 나는 사용해야 합니다.IEnumerable<>
하여 " of 여러 걸쳐번의여에러성의, "개열가능거다니발오류합"의했습니다.IEnumerable
".
샘플 코드:
public List<object> Foo(IEnumerable<object> objects)
{
if (objects == null || !objects.Any())
throw new ArgumentException();
var firstObject = objects.First();
var list = DoSomeThing(firstObject);
var secondList = DoSomeThingElse(objects);
list.AddRange(secondList);
return list;
}
- 는 할수있다니습경변▁the를 바꿀 수 있습니다.
objects
be 될개 변수매List
가능한 다중 열거를 피하지만 내가 처리할 수 있는 가장 높은 개체를 얻지 못합니다. - 내가 할 수 있는 또 다른 일은 변환하는 것입니다.
IEnumerable
List
메서드의 시작 부분:
public List<object> Foo(IEnumerable<object> objects)
{
var objectList = objects.ToList();
// ...
}
하지만 이건 그냥 어색해요.
이 시나리오에서는 어떻게 하시겠습니까?
를 .IEnumerable
호출자에게 "이것을 열거하고 싶습니다"라고 말하는 것이 매개 변수입니다.당신이 몇 번을 열거하고 싶은지는 그들에게 말하지 않습니다.
objects 매개 변수를 List로 변경한 다음 가능한 다중 열거를 피할 수 있지만 처리할 수 있는 가장 높은 개체를 얻지 못합니다.
가장 높은 대상을 차지하려는 목표는 고귀하지만, 너무 많은 가정의 여지를 남깁니다.LINQ to SQL 쿼리를 이 메서드에 두 번만 열거할 수 있도록(매번 다른 결과를 얻을 수 있음) 누군가가 이 메서드에 전달하기를 원하십니까?
여기서 의미론적으로 누락된 것은 아마도 메서드의 세부사항을 읽는 데 시간을 들이지 않는 호출자가 한 번만 반복한다고 가정할 수 있다는 것입니다. 그래서 그들은 값비싼 물건을 의미합니다.메소드 서명은 어느 쪽으로도 표시되지 않습니다.
를 메다서서다명변로경니합음으을로 으로써.IList
/ICollection
당신은 적어도 당신의 기대가 무엇인지를 전화를 건 사람들에게 더 명확하게 할 것이고, 그들은 비용이 많이 드는 실수를 피할 수 있습니다.
그렇지 않으면 메소드를 보고 있는 대부분의 개발자가 사용자가 한 번만 반복한다고 가정할 수 있습니다.을 보는 IEnumerable
그것은 매우 중요합니다, 당신은 그것을 하는 것을 고려해야 합니다..ToList()
방법의 시작 부분에서.
아쉽습니다.NET에는 추가/제거 등의 메서드가 없는 IEnumberable + Count + Indexer 인터페이스가 없으므로 이 문제가 해결될 것으로 생각됩니다.
데이터가 항상 반복 가능하다면 걱정할 필요가 없습니다.그러나 롤을 해제할 수도 있습니다. 들어오는 데이터가 클 경우(예: 디스크/네트워크에서 읽기) 특히 유용합니다.
if(objects == null) throw new ArgumentException();
using(var iter = objects.GetEnumerator()) {
if(!iter.MoveNext()) throw new ArgumentException();
var firstObject = iter.Current;
var list = DoSomeThing(firstObject);
while(iter.MoveNext()) {
list.Add(DoSomeThingElse(iter.Current));
}
return list;
}
참고 저는 DoSomething Else의 의미를 조금 바꿨지만, 이것은 주로 롤업되지 않은 사용법을 보여주기 위한 것입니다.예를 들어, 반복기를 다시 포장할 수 있습니다.있고,도 있습니다. 반블록만수있다습니도가 . 좋을 수도 있습니다. 그러면 없습니다.list
은 리고당신은그은신▁would.yield return
반품할 목록에 추가하는 것이 아니라 받는 대로 항목을 변경할 수 있습니다.
용사를 합니다.IReadOnlyCollection<T>
또는IReadOnlyList<T>
에서 대신 대신에IEnumerable<T>
에는 반복하기 전에 카운트를 확인해야 하거나 다른 이유로 여러 번 반복해야 할 수 있음을 명시할 수 있는 장점이 있습니다.
그러나 인터페이스를 사용하기 위해 코드를 재팩터링하여 테스트하기 쉽고 동적 프록시에 친숙하게 만드는 등의 경우 문제가 발생할 수 있는 큰 단점이 있습니다.중요한 점은 에서 상속되지 않는다는 것이며, 다른 컬렉션과 각 읽기 전용 인터페이스에 대해서도 마찬가지입니다.(간단히 말해서, 이는.NET 4.5는 이전 버전과 ABI 호환성을 유지하기를 원했습니다.하지만 그들은 그것을 바꿀 기회조차 잡지 않았습니다.NET 코어.)
이것은 만약 당신이 그것을 얻는다면IList<T>
.IReadOnlyList<T>
,할 수 없습니다!그러나 as를 통과할 수 있습니다.
마내침.IEnumerable<T>
sl에서 입니다.모든 수집 인터페이스를 포함하는 NET 컬렉션입니다.일부 아키텍처 선택에서 벗어날 수 없다는 것을 알게 되면 다른 대안이 다시 떠오를 것입니다.따라서 함수 서명에 사용하여 읽기 전용 컬렉션을 원하는 것을 표현하는 것이 적합하다고 생각합니다.
(항상 다음을 작성할 수 있습니다.)IReadOnlyList<T> ToReadOnly<T>(this IList<T> list)
두 를 모두 하는 경우 때는 .IEnumerable<T>
항상 호환됩니다.)
이것이 절대적인 것은 아니기 때문에 실수로 여러 개의 열거를 하는 것이 문제가 되는 데이터베이스를 많이 사용하는 코드를 작성하는 경우에는 다른 절충을 선호할 수 있습니다.
.NET 6/ C# 10 포함
Enumerable을 사용하여 강제로 열거하지 않고 시퀀스의 요소 수를 결정할 수 있습니다.GetNonEumeratedCount(IEnumberable, Int32) 메서드를 사용해 보십시오.
이 메서드는 다음을 반환합니다.true
의 경우에는source
하지 않고 할 수 . 않으면 열하지않수있결다습니정할고거▁can다있니습수,▁otherwise▁be않▁enum. 그렇지 않으면,false
따라서 추가 구현이 필요한지 확인할 수 있습니다.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
IEnumerable<int> arrayOne = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var canGetCountDirectly = arrayOne.TryGetNonEnumeratedCount(out int theCount);
Console.WriteLine($"Count can be returned directly = {canGetCountDirectly}");
Console.WriteLine($"Count = {theCount}");
}
}
로 마크 를 유지하면서 ▁the▁remove▁if▁▁simple▁could▁you마,taining▁the▁the있ations▁than▁same▁semantics다니▁enumer습수▁but▁by▁multiple크▁main▁the▁answer▁to▁marc할▁the제▁read▁grave▁is거▁aim간히▁is단▁prevent▁really항을목▁one▁toll라중복의동유Any
그리고.First
통화 및 연결:
public List<object> Foo(IEnumerable<object> objects)
{
if (objects == null)
throw new ArgumentNullException("objects");
var first = objects.FirstOrDefault();
if (first == null)
throw new ArgumentException(
"Empty enumerable not supported.",
"objects");
var list = DoSomeThing(first);
var secondList = DoSomeThingElse(objects);
list.AddRange(secondList);
return list;
}
은 당신이 "", ""라고 합니다.IEnumerable
제네릭이 아니거나 적어도 참조 유형으로 제한됩니다.
저는 보통 IEnumberable로 메서드를 오버로드하고 이 상황에서 나열합니다.
public static IEnumerable<T> Method<T>( this IList<T> source ){... }
public static IEnumerable<T> Method<T>( this IEnumerable<T> source )
{
/*input checks on source parameter here*/
return Method( source.ToList() );
}
IEnumberable을 호출하면 수행할 수 있는 방법에 대한 요약 주석을 사용하여 설명합니다.목록으로().
프로그래머는 을 선택할 수 있습니다.여러 작업이 연결되어 있는 경우 상위 수준의 ToList()를 선택한 다음 IList 오버로드를 호출하거나 내 IEnumberable 오버로드가 처리하도록 합니다.
첫 번째 요소만 확인하면 전체 컬렉션을 반복하지 않고 볼 수 있습니다.
public List<object> Foo(IEnumerable<object> objects)
{
object firstObject;
if (objects == null || !TryPeek(ref objects, out firstObject))
throw new ArgumentException();
var list = DoSomeThing(firstObject);
var secondList = DoSomeThingElse(objects);
list.AddRange(secondList);
return list;
}
public static bool TryPeek<T>(ref IEnumerable<T> source, out T first)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
IEnumerator<T> enumerator = source.GetEnumerator();
if (!enumerator.MoveNext())
{
first = default(T);
source = Enumerable.Empty<T>();
return false;
}
first = enumerator.Current;
T firstElement = first;
source = Iterate();
return true;
IEnumerable<T> Iterate()
{
yield return firstElement;
using (enumerator)
{
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
}
}
IReadOnlyCollection을 사용하는 메소드는 여러 번 열거해야 하는 경우에 좋습니다.IE numberable을 IReadOnlyCollection으로 전환하기 위해 언제든지 호출할 수 있는 유틸리티 메소드를 제공하고자 합니다.ToArray()나 ToList()와는 달리 기본 컬렉션의 유형을 변경하는 추가 할당 비용을 피할 수 있습니다.
public static class EnumerableUtils
{
/* Ensures an IEnumerable is only enumerated once */
public static IReadOnlyCollection<T> AsEnumerated<T>(this IEnumerable<T> original)
{
if (original is IReadOnlyCollection<T> originalCollection)
{
return originalCollection;
}
return ImmutableArray.CreateRange(original);
}
}
먼저, 그 경고가 항상 그렇게 큰 의미는 아닙니다.저는 보통 성능의 보틀 넥이 아닌 것을 확인한 후 비활성화했습니다.그것은 단지 의미합니다.IEnumerable
두 번 평가되며, 이는 보통 다음이 아닌 한 문제가 되지 않습니다.evaluation
시간이 오래 걸립니다.시간이 오래 걸리더라도 이 경우에는 처음에 하나의 요소만 사용합니다.
이 시나리오에서는 강력한 linq 확장 방법을 더욱 활용할 수 있습니다.
var firstObject = objects.First();
return DoSomeThing(firstObject).Concat(DoSomeThingElse(objects).ToList();
▁it▁only▁to▁▁is만 평가할 수 있습니다.IEnumerable
이 경우에 한 번 번거롭지만, 먼저 프로파일링하고 정말 문제가 있는지 확인하십시오.
언급URL : https://stackoverflow.com/questions/8240844/handling-warning-for-possible-multiple-enumeration-of-ienumerable
'programing' 카테고리의 다른 글
Azure 함수 - 병렬 실행 제한 (0) | 2023.05.11 |
---|---|
Node.js: ENOSPC 오류란 무엇이며 해결 방법은 무엇입니까? (0) | 2023.05.11 |
Python3의 "함수 주석"의 좋은 용도는 무엇입니까? (0) | 2023.05.11 |
MSBuild를 32비트 모드로 컴파일하려면 어떻게 해야 합니까? (0) | 2023.05.11 |
튜플을 풀 때 힌트를 입력하시겠습니까? (0) | 2023.05.11 |