суббота, 28 декабря 2013 г.

Ответы на LINQ Quiz

Вопрос 1. Ответ: A


Max — это один из агрегирующих LINQ операторов, определенный как метод расширения в классах System.Linq.Enumerable и System.Linq.Queryable.

Max — возвращает максимальное значение вычисленное лямбда выражением, а не элемент имеющий максимальное значение (то есть сначала выполняется проекция с помощью лямбда выражения, а потом ищется максимум).

Вопрос 2. Ответ: D


Произойдет выброс InvalidOperationException исключения: результатом оператора OrderBy будет последовательность содержащая 4 элемента, а Single требует исключительно один элемент. Чтобы вернуть результат «red» необходимо использовать оператор First:
colors.OrderBy (c => c.Length).First()
Так же можно использовать оператор FirstOrDefault (в отличии от FirstFirstOrDefault не выбрасывает исключения если последовательность пуста).

Оператор Single хорош при извлечении строки из таблицы в LINQ to SQL запросе по первичному ключу:
Customer c = dataContext.Customers.Single (c => c.ID == 123);

Вопрос 3. Ответ: D


Компилятор транслирует этот запрос в следующий:
IEnumerable<string> query = colors
  .Where   (c => c.Length > 3)
  .OrderBy (c => c.Length);
Методы Where и OrderBy в данном примере разрешаются как Enumerable.Where и Enumerable.OrderBy которые возвращают тип IEnumerable<T>. T имеет тип string, так как элементы входной последовательности не подлежат проекции.

Вопрос 4. Ответ: C


Переменная с в подзапросе конфликтует с переменной итерации внешнего запроса, так что компилятор сообщит об ошибке. Исправить это можно так:
var query =
  from c in colors
  where c.Length == colors.Max (c2 => c2.Length)
  select c;
Тогда правильным ответом будет (A).

Вопрос 5. Ответ: D


В локальных запросах, подзапросы пересчитываются для каждого элемента в внешней последовательности. Это достаточно не эффективно: мы можем исправить это, запомнив результат подзапроса следующим образом:
int maxLength = colors.Max (c => c.Length);

var query =
  from c in colors
  where c.Length == maxLength
  select c;
В таком случае подзапрос Max будет вычислен только один раз.

Вопрос 6. Ответ: A


Запрос выполняется не во время конструирования, а во время перечисления. Это называется отложенным выполнением. Наш запрос не начнет выполняться до тех пор пока не будет вызван агрегирующий оператор Count, который немедленно произведёт перечисление. К этому времени элемент red будет удален из коллекции.

Любой оператор запроса возвращающий скалярное значение или единственный элемент (такой как Single или First) выполняет немедленное вычисление.

Вопрос 7. Ответ: A


Мы произвели сцепление двух операторов Where, так что наш результирующий запрос возвращает только строки содержащие буквы e и n (только green). Наш запрос идентичен следующему:
var query = colors
  .Where (c => c.Contains ("e"))
  .Where (c => c.Contains ("n"));
и даёт такой же результат что и запрос:
var query = colors.Where (c => c.Contains ("e") && c.Contains ("n"));

Вопрос 8. Ответ: B


Запрос выглядит похожим на предыдущий, однако результаты будут абсолютно разные. Поскольку лямбда выражение ссылается на переменную s, то компилятор производит захват переменной и она становится внешней.

В отношении внешней переменной важно её значение во время выполнения запроса, а не во время конструирования. В нашем примере оба оператора Where используют «n» в своих предикатах, поскольку это значение переменной во время перечисления результата.

Вопрос 9. Ответ: C


Компилятор транслирует запрос следующим образом:
colors.Select (
  c => new
    {
      c = c, 
      middle = c.Substring (1, (c.Length - 2))
    }
  )
  .Where (temp0 => temp0.middle.Contains ("e"))
  .Select (temp0 => temp0.middle)
то есть выполняет проекцию в временный анонимный тип.

Вопрос 10. Ответ: B


Компилятор транслирует запросы содержащие несколько генераторов (from) в вызов метода SelectMany. В LINQ to SQL такой оператор может быть преобразован в различные SQL конструкции, включая внутреннее и внешние соединения. 

Вопрос 11. Ответы: I и IV


Ответы: II и V (если использовать для соединения оператор DefaultIfEmpty)

SelectMany соединения в LINQ to SQL являются самыми гибкими и могут быть оттранслированы в эквисоединения (equi joins) и не-эквисоединения (non-equi joins). Используя DefaultIfEmpty вы можете получить левое внешнее соединения (left outer joins).

Пример простого внутреннего соединения:
from c in dataContext.Customers
from i in dataContext.Invoices
where c.CustomerID == i.CustomerID
select ...
Или используя свойство ассоциации:
from c in dataContext.Customers
from i in c.Invoices
select ...
Пример левого внешнего соединения:
from c in dataContext.Customers
from i in dataContext.Invoices
  .Where (i => c.CustomerID == i.CustomerID)
  .DefaultIfEmpty()
select ...
Или используя свойство ассоциации:
from c in dataContext.Customers
from i in c.Invoices.DefaultIfEmpty()
select ...
Пример внутреннего не-эквисоединения (non-equi inner join):
from t1 in dataContext.Towns
from t2 in dataContext.Towns
where t1.PostCode == t2.PostCode && t1.State.CompareTo (t2.State) < 0
select ...
Мы можем преобразовать этот запрос в внешнее не-эквисоединение (non-equi outer join) следующим образом:
from t1 in dataContext.Towns
from t2 in dataContext.Towns
  .Where (t => t.PostCode == t1.PostCode && t.State.CompareTo (t1.State) < 0)
  .DefaultIfEmpty()
select ...

Вопрос 12. Ответ: I


Ответ: II (если использовать для соединения DefaultIfEmpty)

В LINQ to SQL оператор Join является менее функциональным чем SelectMany, так как он не может преобразовываться в не-эквисоединения (non-equi-joins).

Оператор Join имеет преимущество перед SelectMany в локальных запросах: Join работает быстрее с большими коллекциями, потому что он предварительно загружает внутреннюю (правую) коллекцию в lookup коллекцию.

Вопрос 13. Ответ: B


LINQ to SQL не позволяет вам включать вызовы ваших собственных методов (или не поддерживаемые методы Framework-а) в любом месте, это возможно только в финальной проекции. Если вы попытаетесь это сделать, то произойдет одно из двух:

  • LINQ to SQL выбросит исключение когда ваш запрос будет выполняться (метод XYZ не имеет аналога в SQL)
  • запрос начнет выполняться локально

Вы можете использовать второй сценарий вызывая в запросе метод AsEnumerable. К примеру, следующий LINQ to SQL запрос извлекает все статьи о гриппе и затем использует локальный запрос чтобы получить только те, аннотация которых содержит меньше 100 слов.
var wordCounter = new System.Text.RegularExpressions.RegEx(@"\b(\w|[-'])+\b");
var query = dataContext.Articles
  .Where (a => a.Topic == "influenza")
  .AsEnumerable()
  .Where (a => 
    wordCounter.Matches (a.Abstract).Count < 100
  );
Мы вызываем фильтрацию по регулярному выражению локально, поскольку класс Regex не может быть оттранслирован в SQL.

Вопрос 14. Ответ: D


Следующий пример показывает как это сделать:
var options = new DataLoadOptions();
options.LoadWith <Customer> (c => c.Orders);
dataContext.LoadOptions = options;
Это означает, что когда будет извлекаться работник, то его заказы так же будут извлекаться автоматически.

Вопрос 15. Ответ: A


XElement может иметь только одного предка. Когда вы пытаетесь сделать city так же потомком customer2, LINQ to XML автоматически создает глубокую копию city прежде чем выбросить исключение.

Вопрос 16. Ответ: A


Потомок XElements явно не наследует пространство имен от своего предка. Документ будет выглядеть следующим образом:
<customer xmlns="http://albahari.com/linqquiz">
     <name xmlns="">Bloggs</name>
</customer>
Если вы хотите, чтобы правильным ответом был (B) вы должны сконструировать DOM следующим образом:
var x =
  new XElement (ns + "customer",
    new XElement (ns + "name", "Bloggs")
  );
Этот код преобразуется в такой XML:
<customer xmlns="http://albahari.com/linqquiz">
     <name>Bloggs</name>
</customer>

Вопрос 17. Ответ: A


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

В XDocument наличие XDeclaration не влияет на то будет ли включено описание или нет. XDeclaration лишь позволят указать какую использовать кодировку и что поместить в standalone атрибут.

Комментариев нет:

Отправить комментарий