IEnumerable/seq를 사용하면 안되는 이유
// C#:
int Sum(IEnumerable<int> items)
{
int total = 0;
foreach(var item in items)
{
total += item;
}
return total;
}
// F#
let sum (items: seq<int>) =
let mutable total = 0
for item in items do
total <- total + item
total
"이 함수를 호출하는 것은 영원히 중단될 수 있습니다"라고 말하면 당신이 옳을 것입니다. 다음은
IEnumerable<int> 함수에 전달할 수 있는 seq<int> ( F#의 Sum)에 대한 유효한 값입니다.// C#
IEnumerable<int> GenerateValues()
{
while (true)
{
yield return 1;
}
}
// F#
let generateValues () =
Seq.initInfinite id
이제
Sum(GenerateValues())가 영원히 중단됩니다.이 코드에 어떤 문제가 있습니까?
// C#
interface IConfigValuesProvider
{
IEnumerable<ConfigValue> ConfigValues { get; }
}
var values = myConfigValueProvider.ConfigValues;
if (values.Count() > 0)
{
foreach(var v in values) { ... }
}
// F#
type IConfigValuesProvider =
abstract ConfigValues : seq<ConfigValues>
let values = myConfigValueProvider.ConfigValues
if Seq.length values > 0 then
for v in values do
...
글쎄요, 아마 아무 것도 아니지만, 당신은 정말로 확신할 수 없습니다.
ConfigValues 는 IEnumerable<T> 이므로 기술적으로 무한할 수 있으므로 Count/Seq.length 가 중단될 수 있지만 그럴 가능성은 거의 없습니다. 더 그럴듯하게 들리는 것은 ConfigValues 가 Where 또는 Select 에 대한 호출의 출력으로 구현되고 이를 반복하는 데 계산 비용이 많이 든다는 것입니다. 여기에서 (Count를 호출한 다음 foreach를 수행) 두 번 반복될 가능성이 있습니다. 이는 계산 비용이 많이 든다면 좋지 않습니다. 물론 호출자는 이것이 Array와 유사한 컬렉션처럼 작동할 것으로 예상하지만 실제로 IEnumerable<T>는 그러한 약속을 하지 않습니다. 여기서 잠재적인 해결책은 ConfigValue.ToArray()를 호출하고 그 결과를 사용하는 것이지만 ConfigValues가 실제로 컬렉션일 경우 무의미한 복사본을 만들 것입니다. 우리는 알 수 없으므로 안전하지 않은 가정을 하거나 방어적으로 코딩하고 리소스를 낭비합니다.IEnumerable<T>/seq<T>는 항목 모음을 나타내지 않으므로 항목 모음을 나타내는 데 사용해서는 안 됩니다.그래서 우리는 무엇을 사용해야합니까? 모든 컬렉션이 실제로 컬렉션임을 보증하고 구현하는 또 다른 인터페이스가 있습니까? 예, 있습니다. 2012년 8월 15일 .NET 4.5에 도입된
IReadOnlyCollection<T> 입니다. 보다 구체적이고 진정한 배열과 유사한 동작(인덱싱 지원 포함)을 원하면 IReadOnlyList<T>가 지원합니다. . 나는 인덱스가 있는 모든 것에 대해 IReadOnlyList<T> (배열, List<T> , ImmutableArray<T> 등) 및 IReadOnlyCollection<T> 다른 모든 것에 대해 LinkedList<T> , Queue<T> , Stack<T> 쪽으로 기울고 있습니다. ) ImmutableArray<T>와 같은 구체적인 불변 컬렉션이 특히 반환 유형으로 더 나은 경우가 있습니다. 구체적인 유형을 반환하는 것이 더 큰 가치를 제공하는 것 같습니다. 예를 들어 위대하고 명확한 지침을 찾지 못했습니다. IReadOnlyList<T> 대 ImmutableArray<T> ; 그것에 대한 의견이 있으면 공유하십시오!마지막으로
IEnumerable<T>가 컬렉션을 나타내지 않고 이를 완벽하게 대체할 수 있다면 무슨 소용이 있습니까?IEnumerable<T>는 컬렉션, 무한 시퀀스, 연속 값 계산 등 열거를 지원하는 모든 것입니다. 임의의 무한한 데이터 시퀀스에 대한 매핑을 정의하는 데 완벽한 유형입니다. Where도 반환하는 LINQ 연산자 Select , IEnumerable<T> 를 생각해 보십시오. 이 연산자는 완벽하게 이해되고 더 나은 유형을 사용할 수 없습니다. IMO가 존재하지 않아야 하는 Enumerable.Sum 또는 Enumerable.Count와 같은 스칼라 반환 함수를 생각하지 마십시오. 유한 컬렉션 외에는 의미가 없으며 작동하지도 않습니다.IReadOnlyCollection<T> 및 친구를 .NET에 늦게 추가한 것은 IEnumerable<T>를 컬렉션의 읽기 전용 보기로 널리 사용하는 데 주로 책임이 있다고 생각합니다. 결국 IEnumerable<T>는 2006년 초 .NET 2에, System.Linq는 2007년 말 .NET 3.5에 도착했습니다. 같은 시기에 디자인된 F#의 Seq 모듈은 System.Linq와 동일한 문제로 가득 차 있습니다. ) : Seq.sum , Seq.length , Seq.append , Seq.toList , Seq.toArray 등은 모두 매우 실용적이지만 확실히 건전하지 않습니다.
Reference
이 문제에 관하여(IEnumerable/seq를 사용하면 안되는 이유), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/asik/why-you-probably-shouldnt-use-ienumerableseq-3g6g텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)