문제

나는있다 Enumerable<T> 그리고 각 요소에 대한 작업을 실행할 수있는 방법을 찾고 있습니다. Select 그러나 부작용을 위해. 같은 것 :

string[] Names = ...;
Names.each(s => Console.Writeline(s));

또는

Names.each(s => GenHTMLOutput(s));   
// (where GenHTMLOutput cannot for some reason receive the enumerable itself as a parameter)

나는 시도했다 Select(s=> { Console.WriteLine(s); return s; }), 그러나 그것은 아무것도 인쇄하지 않았습니다.

도움이 되었습니까?

해결책

이것을 얻는 빠른 방법은 다음과 같습니다.

Names.ToList().ForEach(e => ...);

다른 팁

당신은 현재 목록 제네릭 컬렉션에만 존재하는 끊임없이 유능한 foreach를 찾고 있습니다. Microsoft가 이것을 LINQ 방법으로 추가 해야하는지 여부에 대한 온라인에서 많은 토론이 있습니다. 현재 자신의 것을 굴려야합니다.

public static void ForEach<T>(this IEnumerable<T> value, Action<T> action)
{
  foreach (T item in value)
  {
    action(item);
  }
}

동안 All() 메소드는 유사한 능력을 제공하며, 사용 사례는 동작이 아닌 모든 항목에서 술어 테스트를 수행하는 것입니다. 물론, 다른 작업을 수행하도록 설득 될 수 있지만 이것은 의미론을 다소 변화시키고 다른 사람들이 코드를 해석하기가 더 어려워 질 것입니다 (즉, 이는이 사용입니다. All() 술어 테스트 또는 행동의 경우?).

면책 조항 :이 게시물은 더 이상 내 원래 대답과 비슷하지 않고 오히려 내가 얻은 7 년의 경험을 포함합니다. 나는 이것이 고도로 보는 질문이기 때문에 편집을 만들었고 기존 답변 중 어느 것도 실제로 모든 각도를 다루지 않았습니다. 내 원래 답변을보고 싶다면 이 게시물의 수정 기록.


여기서 가장 먼저 이해해야 할 것은 C# LINQ 작업과 같은 것입니다. Select(), All(), Where(), 등, 뿌리가 들어 있습니다 기능적 프로그래밍. 이 아이디어는 기능 프로그래밍의 더 유용하고 접근하기 쉬운 부분을 .NET 세계에 가져 오는 것이 었습니다. 기능 프로그래밍의 핵심 교리는 조작에 부작용이 없기 때문에 이것은 중요합니다. 이것을 과소 평가하기는 어렵습니다. 그러나, 경우 ForEach()/each(), 부작용은 전체 작업의 전체가 적용됩니다. 첨가 each() 또는 ForEach() 다른 LINQ 연산자의 기능적 프로그래밍 범위를 벗어난 것이 아니라 그들에 대한 직접적인 반대.

그러나 나는 이것이 불만족 스럽다고 생각한다. 해결해야 할 실제 문제가 있습니다. 왜이 모든 아이보리 타워 철학이 진정으로 유용 할 수있는 방해가되어야합니까?

당시 C# 디자인 팀에 있었던 Eric Lippert는 여기서 우리를 도울 수 있습니다. 그는 전통적인 것을 사용하는 것이 좋습니다 foreach 고리:

foreach ()]은 언어에 새로운 표현력이 0을 추가합니다. 이렇게하면이 완벽하게 명확한 코드를 다시 작성할 수 있습니다.

foreach(Foo foo in foos){ statement involving foo; }

이 코드로 :

foos.ForEach(foo=>{ statement involving foo; });

그의 요점은 구문 옵션을 자세히 살펴보면 새로운 것을 얻지 못하는 것입니다. ForEach() 확장 대 전통 foreach 고리. 나는 부분적으로 동의하지 않는다. 당신이 이것을 가지고 있다고 상상해보십시오 :

 foreach(var item in Some.Long(and => possibly)
                         .Complicated(set => ofLINQ)
                         .Expression(to => evaluate)
 {
     // now do something
 } 

이 코드는 의미를 분리하기 때문에 의미를 난독하게합니다 foreach 루프 작업의 키워드. 또한 루프 명령을 나열합니다 이전의 루프가 작동하는 시퀀스를 정의하는 작업에. 해당 작업이 먼저오고 싶어하는 것이 훨씬 자연스럽게 느껴지고, 그런 다음 루프 명령을 쿼리 정의의. 또한 코드는 추악합니다. 이것을 쓸 수있는 것이 훨씬 더 좋은 것 같습니다.

Some.Long(and => possibly)
   .Complicated(set => ofLINQ)
   .Expression(to => evaluate)
   .ForEach(item => 
{
    // now do something
});

그러나 여기서도 나는 결국 에릭의 관점으로 돌아 왔습니다. 위에서 볼 수 있듯이 코드가 추가 변수를 요구하고 있음을 깨달았습니다. 이와 같은 복잡한 LINQ 표현식 세트가있는 경우 먼저 LINQ 표현식 결과를 새로운 변수에 할당하여 코드에 귀중한 정보를 추가 할 수 있습니다.

var queryForSomeThing = Some.Long(and => possibly)
                        .Complicated(set => ofLINQ)
                        .Expressions(to => evaluate);
foreach(var item in queryForSomeThing)
{
    // now do something
}

이 코드는 더 자연 스럽습니다. 그것은 foreach 키워드는 루프의 나머지 부분 옆에 그리고 쿼리 정의 후에 다시 돌아옵니다. 무엇보다도 변수 이름은 LINQ 쿼리의 목적을 이해하려고하는 향후 프로그래머에게 도움이되는 새로운 정보를 추가 할 수 있습니다. 다시, 우리는 원하는 것을 본다 ForEach() 운영자는 실제로 언어에 새로운 표현력을 추가하지 않았습니다.

그러나 우리는 여전히 가설의 두 가지 특징이 누락되었습니다. ForEach() 확장 방법 :

  1. 합성 할 수 없습니다. 더 추가 할 수 없습니다 .Where() 또는 GroupBy() 또는 OrderBy()foreach 새로운 명령문을 작성하지 않고 나머지 코드와 인라인을 루프하십시오.
  2. 게으르지 않습니다. 이러한 작업은 즉시 발생합니다. 예를 들어, 사용자가 명령 버튼을 누를 때까지 작동하지 않는 큰 화면에서 하나의 필드로 작업을 선택하는 양식을 가질 수는 없습니다. 이 양식을 사용하면 명령을 실행하기 전에 사용자가 마음을 바꿀 수 있습니다. 이것은 완벽하게 정상입니다 (쉬운 LINQ 쿼리가 있지만 foreach.

물론 당신은 직접 만들 수 있습니다 ForEach() 확장 방법. 다른 몇 가지 답변에는 이미이 방법의 구현이 있습니다. 그다지 복잡한 것은 아닙니다. 그러나 나는 그것이 불필요하다고 생각합니다. 이미 시맨틱 및 운영 스탠드 포인트에서 우리가하고 싶은 일에 맞는 기존 방법이 있습니다. 위의 누락 된 기능은 모두 기존의 사용으로 해결할 수 있습니다. Select() 운영자.

Select() 위의 두 가지 예에 의해 기술 된 변환 또는 투영의 종류에 적합합니다. 그러나 여전히 부작용을 피하는 것을 피할 것임을 명심하십시오. 전화 Select() 원본에서 새 개체 나 투영을 반환해야합니다. 이것은 때때로 익명 유형 또는 동적 객체 (필요한 경우에만)의 사용을 통해 도움이 될 수 있습니다. 원래 목록 변수에서 지속하려면 결과가 필요하면 언제든지 전화 할 수 있습니다. .ToList() 원래 변수에 다시 할당하십시오. 나는 여기에 일하는 것을 선호하는 것을 여기에 추가 할 것이다 IEnumerable<T> 더 구체적인 유형보다 가능한 한 변수.

myList = myList.Select(item => new SomeType(item.value1, item.value2 *4)).ToList();

요약해서 말하자면:

  1. 그냥 고집하십시오 foreach 대부분의 시간.
  2. 언제 foreach 진짜 하지 않을 것입니다 (아마 생각하는 것만 큼 자주 아님). Select()
  3. 사용해야 할 때 Select(), 당신은 일반적으로 익명 유형으로 투영함으로써 일반적으로 (프로그래밍 가능한) 부작용을 피할 수 있습니다.

불행히도 현재 버전의 LINQ에서이를 수행하는 내장 방법은 없습니다. 프레임 워크 팀은 .foreach Extension 메소드를 추가하지 않았다. 다음 블로그 에서이 일이 진행되는 것에 대한 좋은 토론이 있습니다.

http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

그래도 추가하기가 쉽습니다.

public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) {
  foreach ( var cur in enumerable ) {
    action(cur);
  }
}

LINQ 및 IENUMERABLE으로 바로이 작업을 수행 할 수 없습니다. 자체 확장 방법을 구현하거나 열거를 LINQ로 배열로 캐스트 한 다음 Array.Foreach () : 호출해야합니다.

Array.ForEach(MyCollection.ToArray(), x => x.YourMethod());

값 유형 및 스트러크가 작동하는 방식으로 인해 컬렉션이 값 유형이고 컬렉션의 요소를이 방법으로 수정하면 원래 컬렉션의 요소에 영향을 미치지 않습니다.

LINQ는 업데이트 기능이 아닌 쿼리 기능으로 설계되었으므로 ienumerable에서 메소드를 실행하는 확장자를 찾을 수 없습니다.u003CT> 그것은 당신이 방법을 실행할 수 있기 때문에 (잠재적으로 부작용). 이 경우 당신은

foreach (이름의 문자열 이름)
Console.WriteLine (이름);

글쎄, 당신은 또한 표준을 사용할 수 있습니다 foreach 키워드, OneLiner로 형식화하십시오.

foreach(var n in Names.Where(blahblah)) DoStuff(n);

죄송합니다.이 옵션이 여기에있을 자격이 있다고 생각했습니다 :)

목록에서 Foreach 메소드가 있습니다. .tolist () 메소드를 호출하여 열거 가능한 사람을 목록으로 변환 한 다음 그 중에서 Foreach 메소드를 호출 할 수 있습니다.

또는 나는 사람들이 자신의 foreach 방법을 ienumerable에서 정의하는 것에 대해 들었습니다. 이것은 본질적으로 foreach 메소드를 호출하고 대신 확장 방법으로 래핑함으로써 달성 될 수 있습니다.

public static class IEnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> _this, Action<T> del)
    {
        List<T> list = _this.ToList();
        list.ForEach(del);
        return list;
    }
}

병렬 LINQ 사용 :

names.asparallel (). forall (name => ...)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top