2009-08-20 4 views
11

클로저 및 람다 식의 기본 원칙을 얻지 만 장면 뒤에서 무슨 일이 일어나고 있는지, 내 코드에서 사용하는 것이 실용적이지 않은지에 대해 생각하고 있습니다.클로저 및 C#의 람다

static void Main(string[] args) 
    { 
     List<string> names = new List<string>(); 
     names.AddRange(new string[] 
     { 
      "Alan", "Bob", "Chris", "Dave", "Edgar", "Frank" 
     }); 


     names.FindAll(x => x.StartsWith("C")).ForEach(
      i => Console.WriteLine(i)); 

    } 

먼저 ... 이름의 컬렉션을 취하고 문자 C로 시작하는 모든 이름을 반환 다음 예를 고려, 나는이 표현을 쓴 수있는보다 직접적인 방법은 무엇입니까? 둘째, "FindAll"이 일치하는 항목을 보유하는 새 모음에 대한 메모리를 할당하지 않습니까? 나는 문법이 더 우아하다는 것을 분명히 알지만, 큰 컬렉션을 가지고 작업 할 때 나중에 성능 문제에 봉착하지 않도록하고 싶다. 컴파일러는 내 관심사가 무효화되는 장면에서 몇 가지 최적화 부두를 수행합니까?

답변

15

예, FindAll은 새 목록을 만듭니다. 당신은 알고를 IEnumerable 개체를 반환하는 "경우"방법을 기존의리스트를 반복 할

foreach (string name in names.Where(n => n.StartsWith("C"))) 
{ 
    Console.WriteLine(name); 
} 

그러나 캡처 할 지역 변수가 없기 때문에이 코드에는 폐쇄가 없습니다.

+0

좋아, 그럼 아마 아직 폐쇄의 기초를 얻지 못했을 것입니다. 그럼에도 불구하고, 여기에있는 모든 대답은 훌륭하고 길을 조금 더 멀리 이동합니다 ... 모두들 감사합니다. – lJohnson

+1

클로저와 람다의 차이점은 "캡처 할 로컬 변수가 없으므로 해당 코드가 닫히지 않습니다."입니다. – TLDR

2

FindAll 대신 Where을 사용해야합니다. Where은 조건에 맞는 컬렉션을 반복하여 조건에 맞는 새 컬렉션을 만든 다음 THAT를 반복하고 작업을 실행하는 대신 작업을 실행할 수 있습니다.

2

List<T>.FindAll 메서드를 사용하면 새로운 List<T>이 생성되고 반환됩니다.

당신이 다음 번에 가능한 그들의 결과를 하나 개의 항목을 스트리밍 할 많은 방법이있다 LINQ를 사용할 수 있다면, 오히려 완전히 채워진 컬렉션을 반환하는 것보다 :

foreach (var i in names.Where(x => x.StartsWith("C"))) 
{ 
    Console.WriteLine(i); 
} 

있다없이 내장 ForEachIEnumerable<T>에 작용 방법,하지만 당신은 정말 그 기능을 필요로하는 경우는 자신의 내선을 쓸 사소한 :

names.Where(x => x.StartsWith("C")).ForEach(Console.WriteLine); 

// ... 

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

이것은 정확히 어떻게 할 것인가입니다. 목록 작성을 간소화 할 수 있다고 언급했을 수도 있습니다. List names = new List {Alan, Bob, Chris, Dave, Edgar, Frank}} –

12

올바른 "어디"있습니다 사용하는 말을 다른 답변. 추가 점 :

var query = from name in names where name.StartsWith("C") select name; 
    foreach(var result in query) Console.WriteLine(result); 

참고 문체 관심사로, 내가 표현 항상 부작용과 문이없는 부작용을 가지고하는 것이 좋습니다 : 당신은 또한 "여기서"더 좋은 보이게하기 위해 쿼리 이해 구문을 사용할 수 있습니다. 따라서 출력 문제를 수행하기 위해 ForEach 하위 표현식 대신 foreach 을 개인적으로 사용합니다. 많은 사람들이 이에 동의하지 않지만 코드를 더 분명하게 만듭니다.

+3

훌륭한 컨벤션! –

0

표현을 특별히 만드는 이유는 무엇입니까 클로저은 어휘 범위가 지정됩니까?

string prefix = "C"; 
// value of prefix included in scope 
names.FindAll(x => x.StartsWith(prefix)).ForEach(...);  

또는

Func filter = null; 

{ 
    string prefix = "C"; 
    // value of prefix included in scope 
    filter = x => x.StartsWith (prefix);  
} 

// find all names starting with "C" 
names.FindAll (filter).ForEach (...);  

아니면 내가 뭔가를 누락되거나 부당한 가정을 만드는 중이라서?