2010-01-07 4 views
0
List<string> a = new List<string>() { "a", "b", "c" }; 
List<string> b = new List<string>() { "a", "b", "c", "d", "e", "f" }; 

b.RemoveAll(a.Contains); 

Если вы пройдете через b, он будет теперь содержать только d e и f. Может кто-нибудь расширить, что происходит на самом деле, потому что в настоящее время это вообще не имеет никакого смысла.Нечетное выражение выражения лямбда

Редактировать: Я больше говорил об использовании предикатов. Как знать, как передать то, что там?

+8

Мне очень тяжело думать, как новичок. Это имеет для меня смысл. – ChaosPandion

+1

Стоит отметить, что этот фрагмент не работал до .NET 2.0 (и «C# 2.0») ... Компилятор создает соответствующий делегат из метода a.Contains. В режиме до 2.0 вам нужно будет создать делегат самостоятельно (новый Predicate (a.Contains)) – Skurmedel

+0

Ну, класс List не существовал до .NET 2.0, но это, помимо моей точки зрения. – Skurmedel

ответ

6
b.RemoveAll(<function that takes a string and returns true if we want to remove it>) 

не требуется выражение лямбда.

возможно, вы хотели бы, чтобы линия читать

b.RemoveAll(x => a.Contains(x)) 

однако, функция x=> a.Contains(x) это просто функция, которая принимает строку и возвращает логическое значение, указывающее, а содержит ли х. a.Contains уже является функцией, которая делает это.

2

В нем говорится: «Удалите все элементы из b, которые содержатся в a». Таким образом, вы остаетесь только с одним в b, который также не присутствовал в a.

3

смотреть на это так:

foreach(string s in b) 
{ 
    if(a.Contains(s)) 
    b.Remove(s); 
} 

Вы пропусканием немного в статье, если оценки в качестве делегата (управляемый эквивалент указателя функции). Метод RemoveAll разворачивает список и делает все остальное.

+3

Лямбда-часть неправильная. Вы действительно передаете делегата. – ChaosPandion

+0

хорошо пункт. отредактирует – dkackman

+0

Lambdas - это те вещи, в которых работает лямбда-оператор, а также странная стрелка: '=>'. 'А.Содержит '- группа методов, и компилятор автоматически создает для него делегат, который имеет тип, ожидаемый с помощью RemoveAll (' Predicate '). –

0

Для каждого элемента в b, a.Contains() оценивается для этого элемента. Если это правда, оно удаляется.

Итак, вы удаляете каждый элемент из b, который также содержится в a.

Функция «a.Contains» передается как аргумент RemoveAll.

1

Вот немного расширенная версия кода, который показывает, что происходит:

List<string> a = new List<string>() { "a", "b", "c" }; 
List<string> b = new List<string>() { "a", "b", "c", "d", "e", "f" }; 
Predicate<string> ps = a.Contains; 
b.RemoveAll (ps); 
5

{} Синтаксис представляет собой набор инициализатор. Код эквивалентен

List<string> a = new List<string>(); 
a.Add("a"); 
a.Add("b"); 
a.Add("c"); 
List<string> b = new List<string>(); 
b.Add("a"); 
b.Add("b"); 
b.Add("c"); 
b.Add("d"); 
b.Add("e"); 
b.Add("f"); 

b.RemoveAll - это функция, которая вызывает другую функцию и передает ее в строку. Это как это:

foreach(string s in b) { 
    if(FunctionToCall(s) == true) b.Remove(s); 
} 

a.Contains это функция, которая принимает строку и возвращает логическое значение. Таким образом, код может быть изменен на:

foreach(string s in b) { 
    if(a.Contains(s)) b.Remove(s); 
} 

Обратите внимание, что в этом лямбда-синтаксис, вы передаете в «a.Contains» функции - не результат функции! Это как указатель на функцию. RemoveAll ожидает, что примет функцию в виде "bool FunctionName (string input)".

Редактировать: Вы знаете, что представляют собой делегаты? Они немного напоминают указатели на функции: делегат указывает подпись («принимает 2 строки, возвращает int»), а затем вы можете использовать ее как переменную.Если вы не знаете о делегатах, прочитайте Karl Seguins article.

Некоторые делегаты нужны очень часто, поэтому рамочные разработчики .net добавили три типа чрезвычайно распространенных делегатов:

  • предиката: делегат, который принимает T и возвращает логическое значение.
  • Действие: Делегат, который занимает от 1 до 4 параметров и возвращает недействительные
  • функции: делегат, который принимает от 0 до 4 параметров и возвращает T

(бесстыдно скопирована с Jon Скита Answer here)

Таким образом, предикат - это просто имя, данное делегату, так что вам не нужно указывать его самостоятельно.

Если есть какие-либо функции в сборке с подписью

«BOOL YourFunction (строка что-то)», это Predicate<string> и могут быть переданы в любую другую функцию, которая принимает один:

public bool SomeFunctionUsedAsPredicate(string someInput) 
{ 
    // Perform some very specific functionality, i.e. calling a web 
    // service to look up stuff in a database and decide if someInput is good 
    return true; 
} 

// This Function is very generic - it does not know how to check if someInput 
// is good, but it knows what to do once it has found out if someInput is good or not 
public string SomeVeryGenericFunction(string someInput, Predicate<string> someDelegate) 
{ 
    if (someDelegate.Invoke(someInput) == true) 
    { 
     return "Yup, that's true!"; 
    } 
    else 
    { 
     return "Nope, that was false!"; 
    } 
} 

public void YourCallingFunction() 
{ 
    string result = SomeVeryGenericFunction("bla", SomeFunctionUsedAsPredicate); 
} 

Весь смысл заключается в разделении проблем (см. Комментарий в SomeGenericFunction), а также иметь очень общие функции. Посмотрите на мой generic, extensible string encoding function. Это использует делегат Func, а не делегат Predicate, но цель та же.

0

Сигнатура RemoveAll выглядит так ...

public int RemoveAll(Predicate<T> match); 

Predicate<T> является делегат, который принимает и возвращает Ts Bools ...

public delegate bool Predicate<T>(T obj) 

RemoveAll таким образом просят ссылку на метод, который в вашем случае принимает строки и возвращает bools. List<T>.Contains - такой способ. Вы заметите, что подпись на List<T>.Contains соответствует делегат предиката (он принимает Ts и возвращает Bools) ...

public bool Contains(T item); 

RemoveAll будет применяться независимо от предиката передается как «матч» к каждому элементу списка, на котором он (b в вашем случае). Итак, если a.Contains("a"), например, возвращает true, тогда все a будут удалены из списка b. Таким образом, в вашем примере все элементы a, b и c удаляются.

Использование такого инструмента, как .NET Reflector, позволит вам ознакомиться с кодом RemoveAll, и это может помочь прояснить, что происходит под обложками.

Смежные вопросы