7 2_linq_and_csharp
jason.zhu edited this page 2021-02-24 16:21:22 +11:00

Module 2. LINQ and C#

Features of using with LINQ:

  • extension methods
  • lambda expressions

Evolving the Language

LINQ on whiteboard (in design phase):

Sequence<Employee> scotts = employees.Where(Name == "Scott");

Emulate LINQ in C#2.0:

IEnumerable<Employee> scotts =
    EnumerableExtensions.Where(employees, delegate(Employee e)
    {
        return e.Name == "Scott";
    });

LINQ today

var scotts =
    from e in employees
    where e.Name == "Scott"
    select e;

There is a compiler in background working hard enough to achieve this feature

The Power of IEnumerable

Reference:

Both List & array inherit & implement an interface IEnumerable<T>. It can represent various data type that can be be iterated.

You can hide any sort of data structure behind IEnumerable<T> interface

Instead of using generic collection like List as shown below, after using IEnumerable<Employee> we can iterate it using GetEnumerator

Employee[] developers = new Employee[]
{
    new Employee {Id = 1, Name = "Scott"},
    new Employee {Id = 2, Name = "Chris"}
};

transform to

IEnumerable<Employee> developers = new Employee[]
{
    new Employee {Id = 1, Name = "Scott"},
    new Employee {Id = 2, Name = "Chris"}
};

Overall, IEnumerable<T> Interface's utility

Exposes the enumerator, which supports a simple iteration over a collection of a specified type.

Creating an Extension Method

Reference:

e.g. of extention methods

public static class StringExtensions
{
    static public double ToDouble(this string data)
    {
        double result = double.Parse(data);
        return result;
    }
}

To create extension methods:

  • 1st parameter of an exention methods uses this modifier. This parameter is called binding parameter
  • Type of binding parameter is class that want to extend

After creating extensions, we can invoke this static method with instance syntax

string text = "43.35";
double data = text.ToDouble();

Note:

  • Static extension method cannot overwrite existing method of that instance. (e.g. replace ToString())
  • Extension can only exist in the namespace it defined.
  • We can use the extension method as a normal static method

Understanding Lambda Expressions

Reference:

The Lambda Expression in C# is the shorthand for writing the anonymous function. So we can say that the Lambda Expression in C# is nothing but to simplify the anonymous function in C#. As the name suggests, an anonymous method is a method without having a name. Anonymous methods in C# can be defined using the keyword delegate and can be assigned to a variable of the delegate type. In simple terms, an anonymous method is a method without a name.

How to create Lambda Expression in C#

To create a lambda expression in C#, we need to specify the input parameters (if any) on the left side of the lambda operator =>, and we need to put the expression or statement block on the other side.

e.g. LINQ filtering using named method

IEnumerable<string> filteredList = cities.Where(StartsWithL);

public bool StartsWithL(string name)
{
    return name.StartsWith("L");
}

Problem: too many code for a filter method

e.g. LINQ filtering using Anonymous Method

IEnumerable<string> filteredList = cities.Where(delegate(string s )
                { return s.StartsWith("L");});

Problem: too many syntax, and hard to read

Solution to problems above: Lambda Expression, clean and concise

IEnumberable<string> filteredList = 
    cities.Where(s => s.StartsWith("L"));

Using Func and Action Types

Reference:

Why we need generic delegates?

For different methods, we need create different delegates. It leads cumberson codes.

Generic delegates can save us from creating all these functions

Many LINQ operator use this type to work with delegate

3 different generic delegate

3 different generic delegate:

  • Func
  • Action
  • Predicate

Syntax for defining Func type:

Fun<param1_datatype, param2_datatype, ..., return_type> delegate_func_name = new Fun<param1_datatype, param2_datatype, ..., return_type>(method_or_lambda);

After defining generic delegate, we can invoke them like normal delegate

generic delegate + lambda expression is very powerful

Essence of LINQ

LINQ take IEnumerable<T>, and return IEnumerable<T>. Hence, we can chain these together

Using var for implicit Typing

Reference:

var is not dynamic typing, it's deducted before compiling

var can be used to declare any built-in data type or a user-defined type or an anonymous type variable.

  • Implicitly-typed variables must be initialized at the time of declaration;
    • It also cannot be initilaized as NULL
  • Multiple declarations of var variables in a single statement are not allowed.
  • var cannot be used for function parameters.

var's benefit & usage:

  • var in foreach
  • var to replace long IEnumerable<...>

Query Syntax vs. Method Syntax

Reference:

Query Syntax:

  • starts with from
  • filter/find/etc. using where, or orderby
  • ends with select or group

C# LINQ translate Query Syntax into Method Syntax. Query Syntax is more fancier, but more functions are available in Method Syntax.

How to choose:

  • Determined by the query.
  • Target: easier to maintain

Summary

Feature in C# that make LINQ work:

  • Extension: where LINQ live. (using System.Linq). These extension know how to sort/filter, but don't know criteria
  • Lambda: Create criteria for filter/sort using simple syntax
  • Query Syntax