Choosing between fluent syntax and query expression syntax

From our preceding discussion, we found two types of querying syntaxes so far. Let's discuss this further by distinguishing these two syntaxes.

IEnumerable<int> queryInt = 
  intList.Select(i => i * 2); 
int queryIntCount = queryInt.Count(); 

The preceding code snippet is the fluent syntax type. We invoke the Select and Count operators by invoking their extension method in the Enumerable class. Using the fluent syntax, we can also chain the method so it will approach functional programming as follows:

IEnumerable<int> queryInt = 
  intList 
    .Select(i => i * 2); 
    .Count(); 

Another syntax type we can use in querying data in LINQ is query expression syntax. We applied this syntax type when we discussed deferred execution in the previous topic. The code snippet of the query expression syntax is as follows:

IEnumerable<Member> memberQuery = 
  from m in memberList 
  where m.MemberSince.Year > 2014 
  orderby m.Name 
  select m; 

In fact, the fluent syntax and the query expression syntax will do the same thing. The difference between them is only the syntax. Each keyword in the query expression syntax has its own extension method in the Enumerable class. To prove this, we can refactor the preceding code snippet to the following fluent syntax type:

IEnumerable<Member> memberQuery = 
  memberList 
  .Where(m => m.MemberSince.Year > 2014) 
  .OrderBy(m => m.Name) 
  .Select(m => m); 

Indeed, we will get the exact same output for these two types of syntaxes. However, the fluent syntax is closer to the functional approach than the query expression syntax.

Understanding the LINQ fluent syntax

Basically, the LINQ fluent syntax is the extension methods found in the Enumerable class. The method will extend any variable implementing the IEnumerable<T> interface. The fluent syntax takes a lambda expression as the parameter to represent the logic that will be performed in the sequence enumeration. As we discussed earlier, the fluent syntax implemented the method chain so that it can be used in the functional approach. In the beginning of this chapter, we had also discussed the extension method from which the query operator can be invoked directly using the static method from its class, which is the Enumerable class. However, by invoking the method directly from its class, we cannot implement the method chain we usually use in the functional approach. Let's take at the following code, which we can find in the FluentSyntax.csproj project, to demonstrate the advantages of the fluent syntax by invoking the extension method instead of the conventional static method:

public partial class Program 
{ 
  private static void UsingExtensionMethod() 
  { 
    IEnumerable<string> query = names 
      .Where(n => n.Length > 4) 
      .OrderBy(n => n[0]) 
      .Select(n => n.ToUpper()); 
    foreach (string s in query) 
    { 
      Console.WriteLine(s); 
    } 
  } 
} 

The names collection we used in the preceding code is as follows:

public partial class Program 
{ 
  static List<string> names = new List<string> 
  { 
    "Howard", "Pat", 
    "Jaclyn", "Kathryn", 
    "Ben", "Aaron", 
    "Stacey", "Levi", 
    "Patrick", "Tara", 
    "Joe", "Ruby", 
    "Bruce", "Cathy", 
    "Jimmy", "Kim", 
    "Kelsey", "Becky", 
    "Scott", "Dick" 
  }; 
} 

As you can see, we use three query operators when we query the data from a collection in the preceding code. They are the Where, OrderBy, and Select operators. Let's take a look at the following code snippet to make this clear:

IEnumerable<string> query =  
  names 
  .Where(n => n.Length > 4) 
  .OrderBy(n => n[0]) 
  .Select(n => n.ToUpper()); 

Based on the preceding query, we will get the string collection in which each string contains more than four characters. The collection will be sorted in an ascending order by its first letter, and the string will be in uppercase characters. Here's what we get on the console if we run the UsingExtensionMethod() method as shown in the following screenshot:

Understanding the LINQ fluent syntax

Now, let's refactor the preceding query to use the conventional static method. But before we go through it, here are the signatures of the three methods we have used in the preceding query:

public static IEnumerable<TSource> Where<TSource>( 
  this IEnumerable<TSource> source, 
  Func<TSource, bool> predicate 
) 
 
public static IEnumerable<TSource> OrderBy<TSource, TKey>( 
  this IEnumerable<TSource> source, 
  Func<TSource, TKey> keySelector 
) 
 
public static IEnumerable<TResult> Select<TSource, TResult>( 
  this IEnumerable<TSource> source, 
  Func<TSource, TResult> selector 
) 

As you can see, all three methods take IEnumerable<TSource> as the first parameter and also return IEnumerable<TResult>. We can use this similarity so that the return from the first method can be fed to the argument of the second method, the return from the second method can be fed to the argument of the third method, and so on.

In the Where() method, we use the second parameter, predicate, to filter the sequence based on it. It's a Func<TSource, bool> delegate, so we can use a lambda expression here. The Func<TSource, TKey> delegate can also be found in the second parameter of the OrderBy() method, which is used as the key to sort the element of the sequence in an ascending order. It can be fed by anonymous method. The last is the Select() method, in which we use its second parameter, selector, to project each element in the sequence in the new form. The anonymous method can also be used as the argument.

Based on the signature of the methods we used in the previous UsingExtensionMethod() method, we can refactor the query as follows:

IEnumerable<string> query = Enumerable.Select(
  Enumerable.OrderBy(Enumerable.Where(names, n => n.Length > 4),
  n => n[0]), n => n.ToUpper());

Here is the complete UsingStaticMethod() method, which is the refactoring code when we use a conventional static method instead of the extension method:

public partial class Program 
{ 
  private static void UsingStaticMethod() 
  { 
    IEnumerable<string> query = 
     Enumerable.Select( 
      Enumerable.OrderBy( 
       Enumerable.Where( 
        names, n => n.Length > 4),  
         n => n[0]), n => n.ToUpper()); 
    foreach (string s in query) 
    { 
      Console.WriteLine(s); 
    } 
  } 
} 

By running the UsingStaticMethod() method, we will get the exact output on the console compared to the UsingExtensionMethod() method.

Understanding the LINQ query expression syntax

A LINQ query expression syntax is a shorthand syntax that we can use to perform LINQ queries. In a query expression syntax, .NET framework provides the keywords for each query operator but not all operators. By using the query syntax, we can invoke the operator like we query the data using SQL in the database. Our code will be more readable and will require less coding when we use the query expression syntax.

In the fluent syntax discussion, we created a query to extract the string from the string list that contains more than four characters, sorted in an ascending order by its first letter and converted to uppercase characters. We can do this using the query expression syntax, as shown in the following code, which we can find in the QueryExpressionSyntax.csproj project:

public partial class Program 
{ 
  private static void InvokingQueryExpression() 
  { 
    IEnumerable<string> query = 
      from n in names 
      where n.Length > 4 
      orderby n[0] 
      select n.ToUpper(); 
    foreach (string s in query) 
    { 
      Console.WriteLine(s); 
    } 
  } 
} 

As you can see, we have refactored the previous code, which uses the fluent syntax for the query expression syntax. Indeed, if we run the InvokingQueryExpression() method, the exact same output will be displayed will be displayed compared to the UsingExtensionMethod() method.

Unfortunately, there are several LINQ operators that have no keyword in the query expression syntax, such as the distinct operator since it doesn't take a lambda expression. In this case, we have to use the fluent syntax, at least in part if we still want to use it. The following are the operators that have a keyword in the query expression syntax:

  • Where
  • Select
  • SelectMany
  • OrderBy
  • ThenBy
  • OrderByDescending
  • ThenByDescending
  • GroupBy
  • Join
  • GroupJoin

Tip

Actually, the compiler converts the query expression syntax into fluent syntax in the compiling process. Although the query expression syntax is sometimes easier to read, we cannot perform all the operations using it; instead, we have to use the fluent syntax, for instance, count operators as we discussed in Deferring LINQ execution topic. What we write in the query expression syntax can also be written in the fluent syntax. Therefore, the fluent syntax is the best approach when we code using LINQ, especially in the functional approach.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset