Learning LINQ Part-2

LINQ (Language INtegrated Query):

1) LINQ is a technique for querying data.

2) We can easily retrieve data from any object that implements the IEnumerable<T> interface using LINQ.

3) LINQ supports IntelliSense and objects are strongly type-safe on the other hand SQL queries are not.

 LINQ Types:

  • LINQ to Object
  • LINQ to ADO.Net  
    • LINQ to SQL
    • LINQ to Dataset
    • LINQ to Entities
  • LINQ to XML

LINQ Architecture
 
LINQ Architecture
LINQ Features:

1.   Automatic Properties:

public class Point

{

    private int _x, _y;

    public int X

    {

        get { return _x; }

        set { _x = value; }

    }

    public int Y

    {

        get { return _y; }

        set { _y = value; }

    }

}

The above code simply defines a class with basic properties. Using LINQ we can write a shorter cleaner version using Automatic Properties which automatically generates the private fields with get/set operations:

public class Point {

    public int X { get; set; }

    public int Y { get; set; }

}

2.   Local Variable Type Inference:

With this feature, the type of the local variable being declared is inferred from the expression used to initialize the variable. This is achieved using the var keyword. It allows us to write the following code:

var num = 50;

var str = “simple string”;

var obj = new myType();

var numbers = new int[] {1,2,3};

var dic = new Dictionary<int,myType>();

The compiler would generate the same IL as if we compiled:

int num = 50;

string str = “simple string”;

myType obj = new myType();

int[] numbers = new int[] {1,2,3};

Dictionary<int,myType> dic = new Dictionary<int,myType>();

Note that there is neither un-typed variable reference nor late-binding happening, instead the compiler is inferring and declaring the type of the variable from the right-hand side of the assignment. As a result, the var keyword is generating a strongly typed variable reference.

3.   Object Initializers & Collection Initializers:

Let’s use the same Point class defined earlier, and suppose we want to define an instance of this class. We will have to create the object and start setting its properties, the code would look like this:

Point p = new Point();

p.X = 0;

p.Y = 0;

This could be rewritten using Objects Initializers and combined into:

Point p = new Point() { X = 0, Y = 0 };

This feature can also be used with collection. Take a look at this example:

List<Point> points = new List<Point> {

    new Point { X = 2,  Y = 5 },

    new Point { X = 1, Y = -10 },

    new Point { X = 3, Y = 0 }

};

Note that the compiler will generate a long hand code equivalent to the above one. It makes calls to the Add() method to add elements to the collection one at a time.

4.   Anonymous Types

The language feature enables us to define inline types without having to explicitly define a class declaration for this type. In other words, imagine we want to use a Point object without defining the class Point (it would be anonymous). We will use the same object initializer syntax discussed earlier, but without the type name:

var p = new {X = 0, Y = 2};

Inside Orcas, you will have full intellisense support. So when you use the variable p you will get a list of properties that this anonymous type has.

5.   Lambda Expressions

C# 2.0 introduced anonymous methods, which allow code blocks to be written “in-line” where delegate values are expected. While anonymous methods provide the power of functional programming languages, the syntax is rather verbose. Lambda expressions provide a more concise, functional syntax for writing anonymous methods. A lambda expression is written as a parameter list (can be implicitly typed), followed by the => token, followed by an expression or a statement block.

As an example, let’s define a delegate type MyDeleg as:

delegate R MyDeleg<A,R>(A arg);

We can then write using anonymous methods:

MyDeleg<int,bool> IsPositive = delegate(int num)

                                                                {

                                   return num > 0;

                               };

Or we can use the new lambda expressions to write:

MyDeleg<int,bool> IsPositive = num => num > 0;

6.   Extension Methods

Extension methods make it possible to extend existing types and constructed types with additional methods, without having to derive from them or recompile the original type. So instead of writing helper methods for objects, they become part of that object itself.

As an example, suppose we want to check a string to see if it is a valid email address. We would do this by writing a function that takes a string as an argument and returns a true/false. With Extension Methods, we can do the following:

public static class MyExtensions

{

    public static bool IsValidEmailAddress(this string s)

    {

        Regex regex = new Regex( @”^[w-.]+@([w-]+.)+[w-]{2,4}$” );

        return regex.IsMatch(s);

    }

}

We defined a static class with a static method containing the Extension Method. Note how the static method above has a this keyword before the first parameter argument of type string. This tells the compiler that this particular Extension Method should be added to objects of type string. And then we can call it from the string as a member function:

using MyExtensions;

string email = Request.QueryString[“email”];

if ( email.IsValidEmailAddress() )

{

    // …

}

It is worth mentioning that LINQ syntax makes use of built-in Extension Methods (e.g. where(), orderby(), select(), sum(), average() and many more) that reside in the new System.Linq namespace in Orcas and define standard query operators that can be used against relational databases, XML and any .NET objects that implement IEnumerable<T>.

7.   Query Syntax

Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery. It is a shorthand for writing queries using the LINQ query operators (i.e. from…where…select). Visual Studio provides full intellisense and compile-time checking support for query syntax.
When the C# compiler encounters a query syntax expression, it actually transforms it into explicit method invocation code that uses Extension Methods and Lambda Expressions.

To explain this, let me give an example:

var result = from c in Customers

             where c.City.StartsWith(“B”)

             orderby c.LastName

             select new { c.FirstName, c.LastName, c.Address };

The above code is equivalent to the following:

var result = Customers.Where( c => c.City.StartsWith(“B”) )

                      .OrderBy( c => c.LastName  )

                      .Select( c => new { c.FirstName, c.LastName, c.Address } );

The advantage of using Query Syntax is that the code is easier and more readable. Also note that a query expression begins with a from clause and ends with either a select or group clause.

One Comment