2010-08-18 5 views
2

Это возвращает логическое значение, основанное на наличии или некорректных идентификаторов.Что на самом деле происходит с IQueryable.Where()?

from t in getAll 
select new Result 
{ 
...    
    bool DetailsAvailable = 
     (db.SaveTrackings.Where(s => s.BundleID == t.bundleID 
            && s.UserID == t.userID) 
         .Count() > 0) ? true : false; 
} 

Это то, что я думаю, что понимаю: .Where() возвращается все записи с идентификаторами соответствия, а затем .Count() просто увидеть, сколько там. Я чувствую, что понимаю, что нам нужно s.

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

Все выражения лямбда использовать оператор лямбда =>, который читается как «идет к». В левой части оператора лямбда указаны параметры ввода (если есть), а правая сторона имеет выражение или оператор блок. Выражение лямбда x => x * x читается «x переходит в x раз x».

Итак, как я полагаю, чтобы понять, что означает, что мой код, основанный на этом, .Where(s «идет в» s.BundleID == t.BundleID ...), так что здесь происходит? Что означает «идет»? Является ли сравнение каждого ID в s всем, доступным в t? Как я понимаю, почему это называется «идет» и что именно происходит?

И тогда она становится все более запутанной ...

В => оператор имеет такой же приоритет, что присваивания (=) и правоассоциативные.

Lambdas используются в методах LINQ запросов в качестве аргументов стандартного запроса методов оператора, таких как Where.

При использовании синтаксиса метода на основе для звонка Если метод в классе перечислимых (как это делается в LINQ к объектов и LINQ к XML) параметр является типом делегата System.Func. Выражение лямбда является наиболее удобным способом создания этого делегата.

Что такое тип делегата System.Func<T, TResult> и как он создается с помощью этого оператора «идет»?

Я не могу просто использовать код, потому что знаю, что он работает, мне нужно понять, как/почему.

+2

Если вам действительно нужно только истинное или ложное, возможно, было бы более эффективно использовать функцию Any, а не где + count? db.SaveTrackings.Any (тот же предикат) вернет true, как только один элемент будет правдой. –

+0

@ Джон поблагодарил, если бы я мог понять, что происходит с этим целым делегатом/лямбдой, пытаясь окунуться в кусочки – BigOmega

+0

, это займет немного времени, тогда он просто «щелкнет». самый простой способ - просто подумать о них как о мини-функциях без имен. синтаксис может быть немного странным, особенно без аргументов ...() => {blah blah blah} получает всех в первый раз. ЧТО ТАКОЕ ЧТО !!!: D –

ответ

2

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

using System; 
using System.Collections.Generic; 

namespace CSharpSandbox 
{ 
    class Program 
    { 
     static IEnumerable<T> Where<T>(IEnumerable<T> input, Func<T, bool> predicate) 
     { 
      foreach (T item in input) 
      { 
       if (predicate(item)) 
        yield return item; 
      } 
     } 

     static void Main(string[] args) 
     { 
      int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
      IEnumerable<int> evens = Where(numbers, n => n % 2 == 0); 
      foreach (int even in evens) 
      { 
       Console.WriteLine(even); 
      } 
     } 
    } 
} 

Конструкция name => someEvaluation создает анонимную функцию, состоящую из следующих частей:

  • name просто имя параметра, тип выводится из его использования. Вам нужно имя, чтобы вы могли ссылаться на аргумент, переданный в функции.
  • => - это начало вашего тела анонимных функций, объем тела - это одно выражение.
  • someEvaluation - это тело вашей анонимной функции, состоящее из одного выражения.

В нашем случае Func<T, bool> определяет функцию, которая принимает один параметр типа T и возвращает выходной сигнал типа bool. (Если бы мы использовали Func<T, U, bool>, мы берем два входа типа T и U и возвращают bool. Последний параметр типа в Func определении, возвращаемое значение.)

Вы можете вызвать экземпляр Func точно так, как вы вызываете любую другую функцию. Если func принимает параметры, вы передаете их, как и ожидалось, ваши параметры привязаны к именам переменных, которые вы определили. Когда вы вызываете функцию, поток управления будет прыгать внутри вашей функции и оценивать ее результаты.

В принципе, вам не нужно анонимно создавать Func. Вы можете передать любую функцию, которая имеет подпись совместимого типа, такую ​​как:

static bool IsEven(int n) 
    { 
     return n % 2 == 0; 
    } 

    static void Main(string[] args) 
    { 
     int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
     IEnumerable<int> evens = Where(numbers, IsEven); 
     foreach (int even in evens) 
     { 
      Console.WriteLine(even); 
     } 
    } 

Эта программа производит тот же результат. Фактически, за кулисами синтаксис name => expression является синтаксическим сахаром; когда он скомпилируется, C# создаст производную частную функцию со скрытым именем и преобразует ее в формат выше.

+0

Возможно, это тоже помогло бы: http://stackoverflow.com/questions/2294053/explaining-functional-programming-to-object-oriented-programmers-and-less-technic/2294279#2294279 – Juliet

+0

Удерживайте секунду. В первом примере вы выписали функцию. Это просто, чтобы продемонстрировать, что происходит, или действительно ли это реализовано? Поскольку я получаю то, что происходит, я просто не понимаю. Например, если я делаю cout >> компьютер сообщает графической карте выплескивать текст на мой монитор. Однако я не знаю, КАК это происходит, я просто знаю, что они работают. – BigOmega

+0

@ Ryan: да, функция выше действительно * is * как вы реализуете функцию Where. Неясно, какую часть вы не понимаете. Для чего стоит, большинство C# заполнено синтаксическим сахаром, который может иногда скрывать основные детали реализации. Функция, содержащая 'yield return whatever', преобразуется в класс, реализующий' IEnumerable ', который сам является конечным автоматом, который переходит к следующему шагу каждый раз, когда вы вызываете его функцию' MoveNext() 'Enumerator. (...) – Juliet

2

Если вам это нравится, подумайте о s как переменной типа SaveTracking. Он выполняет итерацию по каждому s в вашей коллекции/таблице и тестирует значение его BundleID.

t - та же идея - это похоже на повторение всей возвращаемой коллекции от getAll.

Это как SQL псевдокоде:

SELECT * FROM SaveTracking INNER JOIN GetAll 
    ON BundleID AND UserID 

Для более глубокого технического описания того, что происходит с лямбда-выражения, проверить Jon Skeet's book C# In Depth. Глава 9, стр. 230. Я нашел эту книгу очень полезной.

+0

Это не помогает, хотя, потому что я уже это понимаю, и пример «думать об этом как это» не то, что мне нужно, я пытаюсь понять, что именно на самом деле делает компьютер, Поведение – BigOmega

0

Лямбда-выражения являются просто способом сократить код, но он делает точно такие же вещи, как объявить метод, который соответствует типу делегата System.Func<T, TResult>

Я считаю, что C# преобразует Ламбу к способу, в фоновом режиме, когда компиляции и это выглядит следующим образом:

bool LambdaExpression(YourType s) 
{ 
    return s.BundleID == t.bundleID && s.UserID == t.userID; 
} 
Смежные вопросы