문제

가능한 복제 :
ienumerable 인터페이스에 Foreach Extension 메소드가없는 이유는 무엇입니까?

LINQ-Y 코드를 작성할 때 알았습니다 .ForEach() 사용하기에 좋은 관용구입니다. 예를 들어, 다음은 다음 입력을 취하고 이러한 출력을 생성하는 코드입니다.

{ "One" } => "One"
{ "One", "Two" } => "One, Two"
{ "One", "Two", "Three", "Four" } => "One, Two, Three and Four";

그리고 코드 :

private string InsertCommasAttempt(IEnumerable<string> words)
{
    List<string> wordList = words.ToList();
    StringBuilder sb = new StringBuilder();
    var wordsAndSeparators = wordList.Select((string word, int pos) =>
        {
            if (pos == 0) return new { Word = word, Leading = string.Empty };
            if (pos == wordList.Count - 1) return new { Word = word, Leading = " and " };
            return new { Word = word, Leading = ", " };
        });

    wordsAndSeparators.ToList().ForEach(v => sb.Append(v.Leading).Append(v.Word));
    return sb.ToString();
}

interjected를 기록하십시오 .ToList() 전에 .ForEach() 두 번째에서 마지막 줄에.

왜 그런가요? .ForEach() 확장 방법으로 사용할 수 없습니다 IEnumerable<T>? 이와 같은 예를 들어, 그것은 이상하게 보입니다.

도움이 되었습니까?

해결책

왜냐하면 ForEach(Action) 이전에 존재했습니다 IEnumerable<T> 존재했다.

다른 확장 방법과 함께 추가되지 않았기 때문에 C# 디자이너는 그것이 나쁜 디자인이라고 생각하고 선호한다고 가정 할 수 있습니다. foreach 건설하다.


편집하다:

원한다면 자신만의 확장 방법을 만들 수 있습니다. List<T> 그러나 그것은 구현하는 다른 수업에 효과가있을 것입니다. IEnumerable<T>.

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

다른 팁

Eric Lippert에 따르면, 이것은입니다 대부분 철학적 이유로. 전체 게시물을 읽어야하지만 여기에 내가 염려하는 한 요점이 있습니다.

나는 철학적으로 두 가지 이유로 그러한 방법을 제공하는 것에 반대하고 있습니다.

첫 번째 이유는 그렇게 수행하면 다른 모든 시퀀스 연산자가 기반으로하는 기능적 프로그래밍 원칙을 위반하기 때문입니다. 분명히이 방법에 대한 호출의 유일한 목적은 부작용을 일으키는 것입니다.

표현의 목적은 부작용을 일으키지 않고 값을 계산하는 것입니다. 진술의 목적은 부작용을 일으키는 것입니다. 이 물건의 호출 사이트는 표현과 같이 끔찍한 것처럼 보일 것입니다 (그러나, 방법이 무효 회복이기 때문에 표현식은“명세서 표현”컨텍스트에서만 사용될 수 있습니다.)

부작용에만 유용한 유일한 시퀀스 연산자를 만드는 것은 나와 잘 어울리지 않습니다.

두 번째 이유는 그렇게하면 언어에 새로운 표현력이 0이되기 때문입니다.

왜냐하면 ForEach() ienumerable에서는 다음과 같은 각 루프마다 정상입니다.

for each T item in MyEnumerable
{
    // Action<T> goes here
}

나는 단지 여기서 추측하고 있지만, ienumerable에 foreach를 넣으면 부작용이 생길 것입니다. "사용 가능한"확장 방법이 부작용을 일으키지 않아서 Foreach와 같은 명령적인 방법을 배치하면 API가 추측 할 수 있습니다. 또한 Foreach는 게으른 컬렉션을 초기화합니다.

개인적으로 나는 부작용이 부작용을 가진 부작용을 유지하기 위해 내 자신을 추가하려는 유혹을 막았습니다.

Foreach는 Ilist에 있지 않습니다. 목록에 있습니다. 당신은 당신의 예에서 구체적인 목록을 사용하고있었습니다.

솔직히 말해서 .foreach (action)가 ienumerable에 포함되지 않았지만, 옳고, 잘못되었거나 무관심한 지 모르겠습니다. 그것이 바로 그 방식입니다 ...

그러나 다른 의견에 언급 된 성능 문제를 강조하고 싶었습니다. 컬렉션을 통한 방법을 기반으로 성능이 히트합니다. 그것은 비교적 사소하지만 그럼에도 불구하고 확실히 존재합니다. 다음은 관계를 보여주는 엄청나게 빠르고 조잡한 코드 스 니펫이 있습니다.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Start Loop timing test: loading collection...");
        List<int> l = new List<int>();

        for (long i = 0; i < 60000000; i++)
        {
            l.Add(Convert.ToInt32(i));
        }

        Console.WriteLine("Collection loaded with {0} elements: start timings",l.Count());
        Console.WriteLine("\n<===============================================>\n");
        Console.WriteLine("foreach loop test starting...");

        DateTime start = DateTime.Now;

        //l.ForEach(x => l[x].ToString());

        foreach (int x in l)
            l[x].ToString();

        Console.WriteLine("foreach Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");
        Console.WriteLine("List.ForEach(x => x.action) loop test starting...");

        start = DateTime.Now;

        l.ForEach(x => l[x].ToString());

        Console.WriteLine("List.ForEach(x => x.action) Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");

        Console.WriteLine("for loop test starting...");

        start = DateTime.Now;
        int count = l.Count();
        for (int i = 0; i < count; i++)
        {
            l[i].ToString();
        }

        Console.WriteLine("for Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");

        Console.WriteLine("\n\nPress Enter to continue...");
        Console.ReadLine();
    }

그래도 이것에 너무 많이 매달리지 마십시오. 성능은 애플리케이션 설계의 통화이지만 애플리케이션은 실제 성능에 닿지 않는 한 유용성 문제를 일으키는 경우, 실제 비즈니스 프로젝트의 통화이기 때문에 유지 관리 및 재사용을 코딩하는 데 중점을 둡니다.

Foreach는 콘크리트 클래스에서 구현됩니다 List<T>

단지 추측하지만 목록은 열거자를 만들지 않고 항목을 반복 할 수 있습니다.

public void ForEach(Action<T> action)
{
    if (action == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    for (int i = 0; i < this._size; i++)
    {
        action(this._items[i]);
    }
}

이것은 더 나은 성능으로 이어질 수 있습니다. ienumerable을 사용하면 일반적인 루프를 사용할 수있는 옵션이 없습니다.

"선택"이라고합니다 IEnumerable<T>나는 깨달았습니다. 감사합니다.

LINQ는 풀 모델을 따르고 모든 (확장) 방법이 반환됩니다. IEnumerable<T>, 제외하고 ToList(). 그만큼 ToList() 풀 체인을 끝내야합니다.

ForEach() 푸시 모델 세계에서 온 것입니다.

사무엘이 지적한대로이를 위해 자신만의 확장 방법을 작성할 수 있습니다.

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