카드에 대한 유효성 검사 오류를 가져 오는 다음 함수가 있습니다. 내 질문은 GetErrors를 처리하는 것과 관련이 있습니다. 두 메서드 모두 반환 유형이 동일한 IEnumerable<ErrorInfo<
입니다.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
var errors = GetMoreErrors(card);
foreach (var e in errors)
yield return e;
// further yield returns for more validation errors
}
오류를 열거하지 않고 GetMoreErrors
의 모든 오류를 반환할 수 있나요?
생각해보면 이것은 아마도 어리석은 질문이지만 내가 잘못하고 있지 않은지 확인하고 싶습니다.
이것은 결코 어리석은 질문이 아니며, F#에서는 전체 컬렉션에 대한 수율!
과 단일 항목에 대한 수율
을 지원합니다. (꼬리 재귀 측면에서 매우 유용할 수 있습니다...)
안타깝게도 C#에서는 지원되지 않습니다.
그러나 각각 IEnumerable<ErrorInfo
를 반환하는 메서드가 여러 개 있는 경우 Enumerable.Concat
을 사용하여 코드를 더 간단하게 만들 수 있습니다:
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
return GetMoreErrors(card).Concat(GetOtherErrors())
.Concat(GetValidationErrors())
.Concat(AnyMoreErrors())
.Concat(ICantBelieveHowManyErrorsYouHave());
}
하지만 두 구현 사이에는 한 가지 중요한 차이점이 있습니다. 이 구현은 반환된 이터레이터를 한 번에 하나씩만 사용하지만 모든 메서드를 즉시 호출한다는 점입니다. 기존 코드는 다음 오류에 대해 요청하기 전에 GetMoreErrors()
의 모든 메서드를 반복할 때까지 기다립니다.
일반적으로 이것은 중요하지 않지만 언제 어떤 일이 일어날지 이해하는 것이 좋습니다.
이렇게 모든 오류 소스뿐만 설정할 수 있습니다 (존 Skeet& 메소드 이름을 빌려 # 39 의 답).
private static IEnumerable<IEnumerable<ErrorInfo>> GetErrorSources(Card card)
{
yield return GetMoreErrors(card);
yield return GetOtherErrors();
yield return GetValidationErrors();
yield return AnyMoreErrors();
yield return ICantBelieveHowManyErrorsYouHave();
}
그런 다음 그들을 반복할 동시에건간에.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
foreach (var errorSource in GetErrorSources(card))
foreach (var error in errorSource)
yield return error;
}
또는 오류 '와' 셀레스트마니 소스뿐만 병합해야 수 있습니다.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
return GetErrorSources(card).SelectMany(e => e);
}
실행 방법은 '에서' 게테로르수크스 늦춰질 가능성이 없다.
내가 '빠른' yield_ 스니핏 마련했다.
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Author>John Gietzen</Author>
<Description>yield! expansion for C#</Description>
<Shortcut>yield_</Shortcut>
<Title>Yield All</Title>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<Default>items</Default>
<ID>items</ID>
</Literal>
<Literal Editable="true">
<Default>i</Default>
<ID>i</ID>
</Literal>
</Declarations>
<Code Language="CSharp"><![CDATA[foreach (var $i$ in $items$) yield return $i$$end$;]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
기능에 문제가 있는 것은 아니며 원하는 대로 작동하고 있다고 말하고 싶습니다.
Yield는 호출될 때마다 최종 열거형에 요소를 반환하는 것으로 생각하면 되므로, 이와 같이 포리치 루프에 넣으면 호출될 때마다 요소 1개를 반환합니다. foreach에 조건문을 넣어 결과 집합을 필터링할 수 있습니다. (단순히 제외 기준에 양보하지 않는 것만으로)
메서드 후반부에 후속 산출을 추가하면 계속해서 열거형에 요소 1개를 추가하여 다음과 같은 작업을 수행할 수 있습니다.
public IEnumerable<string> ConcatLists(params IEnumerable<string>[] lists)
{
foreach (IEnumerable<string> list in lists)
{
foreach (string s in list)
{
yield return s;
}
}
}
예, 모든 오류를 한 번에 반환할 수 있습니다. 그냥 List<T
또는 ReadOnlyCollection<T
를 반환하면 됩니다.
열거형`을 반환하면 어떤 시퀀스를 반환하는 것입니다. 표면적으로는 컬렉션을 반환하는 것과 동일해 보일 수 있지만 여러 가지 차이점이 있으므로 명심해야 합니다.
컬렉션
시퀀스
IEnumerable<T>
를 반환하면 지연 평가가 가능하지만 List<T>
를 반환하면 그렇지 않습니다).public static class EnumearbleExtensions
{
public static IEnumerable<T> UnWrap<T>(this IEnumerable<IEnumerable<T>> list)
{
foreach(var innerList in list)
{
foreach(T item in innerList)
{
yield return item;
}
}
}
}
이렇게 네 경우엔 이를 사용할 수 있습니다
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
return DoGetErrors(card).UnWrap();
}
private static IEnumerable<IEnumerable<ErrorInfo>> DoGetErrors(Card card)
{
yield return GetMoreErrors(card);
// further yield returns for more validation errors
}
마찬가지로, 할 수 있는 기능 등을 중심으로 래퍼 '와' 그냥 '이동' 을 도게테로스 풀다 캘시테.