Extras

LINQ Quiz

Translations: English | Spanish

Take the following short quiz and test your knowledge of LINQ!

All samples assume the following namespaces are imported:

using System;
using System.Linq;
using System.Data.Linq;
using System.Xml.Linq;
using System.Collections;

and that the following array is defined:

string[] colors = { "green", "brown", "blue", "red" };

OK, let's get started!

Q1. What does the following expression evaluate to?

colors.Max (c => c.Length)

(A)  5
(B)  green
(C)  brown
(D)  Compile-time error
(E)  Exception thrown

Answer

Answer: A

Max is one of the aggregation operators, which are implemented as extension methods in System.Linq.Enumerable and System.Linq.Queryable.

Max returns the maximum value calculated by the lambda expression, not the element that had the maximum value.

Q2. What does this expression evaluate to?

colors.OrderBy (c => c.Length).Single()

(A)  3
(B)  red
(C)  Compile-time error
(D)  Exception thrown

Answer

Answer: D

This throws an InvalidOperationException: the sequence emitted by OrderBy contains four elements, and Single demands exactly one element. To get the result "red", you must use the First operator instead:

colors.OrderBy (c => c.Length).First()

Another option is to use FirstOrDefault (unlike First, FirstOrDefault doesn't throw an exception there are zero elements in the sequence).

Single is good for retrieving a row from a table by primary key, in a LINQ to SQL query:

Customer c =
  dataContext.Customers.Single (c => c.ID == 123);

In this case, you'd want an exception to be thrown if there were two customers with that ID.

Q3. Given the following statement:

var query =
  from c in colors
  where c.Length > 3
  orderby c.Length
  select c;

what type is query?

(A)  int
(B)  string
(C)  IEnumerable<int>
(D)  IEnumerable<string>
(E)  IQueryable<int>
(F)  IQueryable<string>

Answer

Answer: D

The compiler translates this query to:

IEnumerable<string> query = colors
  .Where   (c => c.Length > 3)
  .OrderBy (c => c.Length);

The Where and OrderBy methods, in this case, resolve to Enumerable.Where and Enumerable.OrderBy, which both return IEnumerable<T>. T is inferred to be string because we haven't transformed or projected the input sequence elements in any way.

Q4. What's the output from the following?

var query =
  from c in colors
  where c.Length == colors.Max (c => c.Length)
  select c;

foreach (var element in query)
  Console.WriteLine (element);

That colors array, again, is { "green", "brown", "blue", "red" }

(A)  green followed by brown
(B)  5 followed by 5
(C)  Compile-time error
(D)  Exception is thrown

Answer

Answer: C

The variable, c, inside the subquery, conflicts with the outer query's iteration variable, so the compiler complains.  Here's how to fix it:

var query =
  from c in colors
  where c.Length == colors.Max (c2 => c2.Length)
  select c;

The answer is then (A).

Q5. Assuming we make it syntactically correct, how many times does the Max subquery execute in the preceding example, when query is enumerated?

(A)  once
(B)  twice
(C)  3 times
(D)  4 times

Answer

Answer: D

With local queries, subqueries re-evaluate for each element in the outer sequence. This is somewhat inefficient: we could avoid this by factoring out the subquery as follows:

int maxLength = colors.Max (c => c.Length);

var query
  from c in colors
  where c.Length == maxLength
  select c;  

The Max query then executes just once.

Q6. What does the following example output?

var list = new List<string> (colors);
IEnumerable<string> query = list.Where (c => c.Length == 3);
list.Remove ("red");

Console.WriteLine (query.Count());

(A)  0
(B)  1
(C)  2
(D)  Exception thrown

Answer

Answer: A

Queries execute not when constructed, but when enumerated. This is called lazy or deferred evaluation. Our query doesn't start executing until it encounters the aggregation operator, Count, which forces immediate enumeration. By that stage, red has been removed from the collection.

Any query operator that returns a scalar value or single element (such as Single or First) forces immediate execution.

Q7. What's the output from the following?

string[ ] colors = { "green", "brown", "blue", "red" };

var query = colors.Where (c => c.Contains ("e"));
query     = query.Where  (c => c.Contains ("n"));

Console.WriteLine (query.Count());

(A)  1
(B)  2
(C)  3
(D)  4

Answer

Answer: A

We've chained one Where operator after another, so that our final query considers only strings containing both the letters e and n (only green). Our query is compositionally identical to this:

var query = colors
  .Where (c => c.Contains ("e"))
  .Where (c => c.Contains ("n"));

and gives the same result as this:

var query = colors
  .Where (c => c.Contains ("e")
            && c.Contains ("n"));

Q8. What's the output from the following?

string s  = "e";
var query = colors.Where (c => c.Contains (s));

s         = "n";
query     = query.Where  (c => c.Contains (s));

Console.WriteLine (query.Count());

(A)  1
(B)  2
(C)  3
(D)  4

Answer

Answer: B

This query looks very much like the last one, but the result is very different! Because the variable s is referenced from within a lambda expression, it's captured by the compiler and becomes an outer variable.

With an outer variable, what matters is its value at the time the query executes—not its value at the time the query was constructed. In our example, both Where operators end up using "n" in their predicates, because this is the value of s when the query was actually enumerated.

Q9. How does the compiler resolve the let clause, in the following query?

from c in colors
let middle = c.Substring (1, c.Length - 2)
where middle.Contains ("e")
select middle

(A)  By translating it into a call to Enumerable.Let
(B)  By expanding middle into c.Substring (1, c.Length - 2) in the where and select clauses
(C)  By projecting it into a temporary anonymous type

Answer

Answer: C

Here's how the compiler translates this query:

colors.Select (
  c => new
    {
      c = c, 
      middle = c.Substring (1, (c.Length - 2))
    }
  )
  .Where (temp0 => temp0.middle.Contains ("e"))
  .Select (temp0 => temp0.middle)

To see how the compiler translates comprehension queries, replace colors with colors.AsQueryable(), and then run the query in LINQPad. The translation displays in the lambda tab.

Q10. The compiler translates queries containing multiple generators (i.e., multiple from clauses) into:

(A)  Multiple Selects
(B)  SelectMany
(C)  Join

Answer

Answer: B

Queries containing multiple generators translate to SelectMany.  LINQ to SQL, in turn, translates SelectMany into a variety of SQL constructs, including inner and outer SQL joins.

Q11. A LINQ to SQL query that uses multiple from clauses (or SelectMany) can perform the equivalent of which of the following kind(s) of SQL JOIN:

I.    Inner joins
II.   Left outer joins
III.  Full outer joins
IV.  Non-equi inner joins
V.   Non-equi outer joins

Answer

Answer: I and IV

Answer: II and V (in conjunction with DefaultIfEmpty)

With LINQ to SQL, SelectMany-based joins are the most flexible, and can perform both equi and non-equi joins. Throw in DefaultIfEmpty, and you can do left outer joins as well!

Here's an example of a simple inner join:

from c in dataContext.Customers
from i in dataContext.Invoices
where c.CustomerID == i.CustomerID
select ...

Or, using an association property:

from c in dataContext.Customers
from i in c.Invoices
select ...

A left outer join:

from c in dataContext.Customers
from i in dataContext.Invoices
  .Where (i => c.CustomerID == i.CustomerID)
  .DefaultIfEmpty()
select ...

 Or, using an association property:

from c in dataContext.Customers
from i in c.Invoices.DefaultIfEmpty()
select ...

Here's an non-equi inner join that queries post codes that cross states:

from t1 in dataContext.Towns
from t2 in dataContext.Towns
where t1.PostCode == t2.PostCode
      && t1.State.CompareTo (t2.State) < 0
select ...

We can turn this into an non-equi outer join as follows:

from t1 in dataContext.Towns
from t2 in dataContext.Towns
  .Where (t => t.PostCode == t1.PostCode
            && t.State.CompareTo (t1.State) < 0)
  .DefaultIfEmpty()
select ...

Q12. A LINQ to SQL query that uses join clauses can perform the equivalent of which of the following kind(s) of SQL JOIN

I.    Inner joins
II.   Left outer joins
III.  Full outer joins
IV.  Non-equi inner joins
V.   Non-equi outer joins

Answer

Answer: I

Answer: II (in conjunction with DefaultIfEmpty)

Join is the not as powerful than SelectMany in LINQ to SQL (it cannot perform non-equi-joins.)

The big advantage of Join over SelectMany is not in LINQ to SQL, but in local queries: Join is much faster with large collections because it preloads the inner sequence into a keyed lookup.

Q13. A LINQ to SQL query can include calls to your own local methods:

A. In Where clauses only
B. In the final projection only
C. Anywhere in the query
D. Not at all

Answer

Answer: B

In a LINQ to SQL query, you cannot include calls to your own local methods (or unsupported Framework methods) in any place other than the final projection. If you try to do otherwise, one of two things will happen:

  • LINQ to SQL will throw an exception when the query executes ("method XYZ has no translation to SQL")
  • the query will be executed locally from that point on.

You can force the second scenario by calling  AsEnumerable on the query. For instance, the following uses a LINQ to SQL query to retrieve all articles on influenza, and then uses a local query to narrow the results down to only those articles whose abstract is less than 100 words:

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
  );

We have to run the regular expressions filter locally, because Regex has no translation in SQL.

Q14. In LINQ to SQL, to request that an entity’s association properties be populated along with the entity (in a single round trip), you would:

(A)  set DelayLoaded to false in the Association attribute
(B)  set EagerLoad to true in the Association attribute
(C)  use a DataLoadOptions object, and call AssociateWith
(D)  use a DataLoadOptions object, and call LoadWith

Answer

Answer: D

Here's an example:

var options = new DataLoadOptions();
options.LoadWith <Customer> (c => c.Orders);
dataContext.LoadOptions = options;

This ensures that when a customer is retrieved, so are the customer's orders.

Q15. What does the following example print?

var city = new XElement ("city", "Seattle");

var customer1 = new XElement ("customer", city);
var customer2 = new XElement ("customer", city);

city.SetValue ("London");
Console.WriteLine (customer2.Element ("city").Value);

(A)  Seattle
(B)  London
(C)  An exception is thrown

Answer

Answer: A

An XElement can have only one parent. When you try and make city also the child of customer2, LINQ to XML automatically makes a deep clone of city, rather than throwing an exception.

Q16. In the following example, what’s the namespace of the inner element name?

XNamespace ns = "http://albahari.com/linqquiz";

var x =
  new XElement (ns + "customer",
    new XElement ("name", "Bloggs")
  );

(A)  "" (empty string)
(B)  "http://albahari.com/linqquiz"
(C)  "name"

Answer

Answer: A

Child XElements do not implicitly inherit a namespace from their parent. Here's what the XML serialization of our DOM would look like:

<customer xmlns="http://albahari.com/linqquiz">
     <name xmlns="">Bloggs</name>
</customer>

If we wanted answer (B), we'd have to construct the DOM in the following manner instead:

var x =
  new XElement (ns + "customer",
    new XElement (ns + "name", "Bloggs")
  );

This would translate to the following XML:

<customer xmlns="http://albahari.com/linqquiz">
     <name>Bloggs</name>
</customer>

Q17. When you call Save on an XElement or XDocument to write its content to a file, an XML declaration is included in the output:

(A)  Always
(B)  Never
(C)  Only if an XDeclaration object is present

Answer

Answer: A

An XML declaration is always written, unless you instead provide an XmlWriter and instruct the writer explicitly not to emit the declaration.

With an XDocument, the presence of an XDeclaration has no effect on whether an XML declaration is written. An XDeclaration merely hints the writer as to what encoding to use, and what to put in the standalone attribute.

 

C# 12 in a Nutshell
Buy from amazon.com Buy print or Kindle edition
Buy from ebooks.com Buy PDF edition
Buy from O'Reilly Read via O'Reilly subscription