Académique Documents
Professionnel Documents
Culture Documents
Table of Contents:
I.
INTRODUCTION................................................................................................................................................................................................................................................................ 2
II.
PRE-REQUISITES ............................................................................................................................................................................................................................................................... 2
III.
OVERVIEW ....................................................................................................................................................................................................................................................................... 3
IV.
V.
VI.
A.
B.
C.
D.
VII.
A.
B.
C.
VIII.
LANGUAGE INTEGRATION.......................................................................................................................................................................................................................................... 10
IX.
TYPE CHECKING.............................................................................................................................................................................................................................................................. 11
X.
XI.
LINQ FLAVORS................................................................................................................................................................................................................................................................ 12
XII.
XIII.
XIV.
LINQ TO XML.............................................................................................................................................................................................................................................................. 13
XV.
1.
2.
3.
4.
a.
b.
c.
5.
6.
7.
a.
b.
c.
d.
8.
a.
b.
c.
d.
9.
10.
XVI.
I.
CONCLUSION: ............................................................................................................................................................................................................................................................ 30
Introduction
My this article explains few of main and important concepts of LINQ and C#. The article explains LINQ in detail, and
covers almost every concept of LINQ and C# 2.0 and 3.0.This is an effort to put together the important concepts at one place for ease
of follow. I will explain the topics by giving simple examples, rather than explaining too much theory behind the examples.
II.
Pre-requisites
The reader of this article should be aware of the LINQ term.
The reader should have basic knowledge of SQL.
III.
Overview
LINQ is so dynamic that it could be described in several ways as,
LINQ is a uniform programming model for any kind of data. LINQ enables you to query and manipulate data with a
consistent model that is independent from data sources.
LINQ is just another tool for embedding SQL queries into code.
LINQ is yet another data abstraction layer.
IV.
What Is LINQ?
In my terms LINQ is actually a methodology that simplifies and unifies the implementation of any kind of data access. LINQ does not
force you to use a specific architecture; it facilitates the implementation of several existing architectures for accessing data.
LINQ is a programming model that introduces queries as a first-class concept into any Microsoft .NET language. However, complete
support for LINQ requires some extensions in the language used.
These extensions boost productivity, thereby providing a shorter, meaningful, and expressive syntax to manipulate data.
Examining a simple LINQ query:
var query = from c in Customers
where c.Country == "Italy"
select c.CompanyName;
The SQL-like syntax used in LINQ is called a query expression, but remember LINQ is not the same as embedded SQL
Original content of this article: http://language-integrated-query.com/Linq_CSharp_3.0_Features.aspx
V.
The compiler when compiles the above code generates the following this code:
Customer[] Customers = GetCustomers();
IEnumerable<Customer> query =
Customers .Where( c => c.Country == "Italy" );
Look at another query expression:
var query = from c in Customers
where c.Country == "Italy orderby c.Name
select new { c.Name, c.City };
and the code when compiled,
var query = Customers.Where( c => c.Country == "Italy" ).OrderBy( c => c.Name ).Select( c => new { c.Name, c.City } );
Therefore we see the compiler internally treats this SQL type query as a simple C# lambda expressions query.
One important thing about LINQ to keep in mind is that a LINQ query is not really executed until there is access to the query result,
this is also called on demand loading or lazy loading,
e.g.
1. var query = from c in Customers ...
foreach ( string name in query ) ...
2. var query = from c in Customers ...
List<Customer> customers = query.ToList();
In both the above mentioned examples,the LINQ query does not execute in the first line actually ,it is executed in the second line
when that query variable is actually addressed or used.Write a code and try it yourself .
VI.
LINQ works on relational and hierarchical model, rather than explaining theory, I would explain the concept with these examples,
In a relational model:
var query = from c in Customers join o in Orders on c.CustomerID equals o.CustomerID
select new { c.CustomerID, c.CompanyName, o.OrderID };
In a hierarchical model:
var query = from c in Customers from o in c.Orders
select new { c.Name, o.Quantity, o.Product. ProductName };
The above two statements clearly states both the models, if you are aware of SQL queries, you can get the above given examples.
Follow below mentioned scenarios,
A. Type declarations with simple relationships :
class Customer
{
public string Name;
public string City;
public Order[] Orders;
}
public class Order
{
public int Quantity;
public Product Product;
}
public class Product
{
public int ProductId;
public decimal Price;
public string ProductName;
}
B. Type declarations with two-way relationships :
public class Customer
{
public string Name;
public string City;
public Order[] Orders;
}
public class Order
{
public int Quantity;
public Product Product;
public Customer Customer;
}
public class Product
{
public int ProductId;
public decimal Price;
public string ProductName;
public Order[] Orders;
}
C. Querying the graph of objects:
VII.
XML Manipulation
LINQ has a different set of classes and extensions to support the manipulation of XML data.
e.g. A fragment of an XML file of orders:
<?xml version="1.0" encoding="utf-8" ?>
<orders xmlns="http://schemas.devleap.com/Orders">
<order idCustomer="ALFKI" idProduct="1" quantity="10" price="20.59"/>
<order idCustomer="ANATR" idProduct="5" quantity="20" price="12.99"/>
<order idCustomer="KOENE" idProduct="7" quantity="15" price="35.50"/>
</orders>
{
order = new Order();
order.CustomerID = xmlOrders.GetAttribute( "idCustomer" );
order.Product = new Product(); order.Product.IdProduct = Int32.Parse( xmlOrders.GetAttribute( "idProduct" ) );
order.Product.Price = Decimal.Parse( xmlOrders.GetAttribute( "price" ) );
order.Quantity = Int32.Parse( xmlOrders.GetAttribute( "quantity" ) );
orders.Add( order );
}
break;
}
}
B. An XQuery like the following one to select nodes :
for $order in document("Orders.xml")/orders/order return $order
C. Reading the XML file using LINQ to XML :
XDocument xmlOrders = XDocument.Load( "Orders.xml" );
XNamespace ns = "http://schemas.devleap.com/Orders";
var orders = from o in xmlOrders.Root.Elements( ns + "order" )
select new Order {
CustomerID = (String)o.Attribute( "idCustomer" ),
Product = new Product {
IdProduct = (Int32)o.Attribute("idProduct"), Price = (Decimal)o.Attribute("price")
},
Quantity = (Int32)o.Attribute("quantity")
};
VIII.
Language Integration
Language integration is a fundamental aspect of LINQ.It allows you to write code such as the following:
var query =
from c in Customers
where c.Country == "Italy" orderby c.Name
select new { c.Name, c.City };
Instead of writing this code:
var query = Customers
.Where( c => c.Country == "Italy" )
.OrderBy( c => c.Name )
.Select( c => new { c.Name, c.City } );
LINQ enables a more declarative style of coding for C# and Visual Basic.
In SQL, we describe what you want. In C#, we describe how to obtain the expected result.
Declarative programming can take advantage of services offered by compilers and frameworks, and in general it is easier to
read and maintain.
This single feature can be the most important one because it boosts programmers productivity.
IX.
Type Checking
Another important aspect of language integration is type checking. Whenever data is manipulated by LINQ, no unsafe cast is
necessary. Data is always strongly typed, including both the queried collections and the single entities that are read and returned.
This enables the use of Visual Studio features such as IntelliSense and Refactoring, even with LINQ queries.
X.
The type system of the Microsoft .NET Framework and the type system of SQL Server are different.Using LINQ, we give
precedence to the .NET type system because it is the one supported by any language that hosts a LINQ query.It is necessary to convert
many types of data between these two worlds. LINQ handles this conversion for you automatically, making the differences in type
XI.
LINQ Flavors
LINQ is a technology that covers many data domains. Some of these domains are included in those LINQ Flavors that Microsoft
provides as part of the .NET 3.5 Framework, as shown in below:
XII.
LINQ to Objects
LINQ to Objects has the goal of manipulating collections of objects, which can be related to each other to form a hierarchy or a
graph.From a certain point of view, LINQ to Objects is the default implementation used by a LINQ query.LINQ to Objects is enabled
including the System.Linq namespace.
XIII.
LINQ to ADO.NET
LINQ to ADO.NET includes different LINQ implementations that share the need to manipulate relational data. It includes other
technologies that are specific to each particular persistence layer:
LINQ to SQL
Handles the mapping between custom types in C# and the physical table schema
LINQ to Entities
Is in many ways similar to LINQ to SQL. However, instead of using the physical database as a persistence layer, it uses a
conceptual Entity Data Model (EDM). The result is an abstraction layer that is independent from the physical data layer.
LINQ to DataSet
Makes it possible to query a DataSet using LINQ
XIV.
LINQ to XML
LINQ to XML offers a slightly different syntax that operates on XML data, allowing query and data manipulation.This query
corresponds to the following C# 3.0 syntax:
var book =
new XElement( "Book",
new XAttribute( "Title", "Introducing LINQ" ), from person in team
where person.Role == "Author select new XElement( "Author", person.Name ) );
XV.
You must be aware of this concept very well, but I wanted to cover this in my way taking simple examples.
Lets take Min() function of C# for example,
Problem:
The Min function, following is the issue
int Min( int a, int b )
{ if (a < b) return a; else return b; }
object Min( object a, object b )
{ if (a < b) return a; else return b; }
IComparable Min( IComparable a, IComparable b ) { if (a.CompareTo( b ) < 0) return a; else return b; }
int a = 5, b = 10;
int c = (int) Min( a, b );
I hope you got the issue, yes type casting.
C# 2.0 solved this problem with generics.The basic principle of generics is that type resolution is moved from the C# compiler to
the jitter. Here is the generic version of the Min function:
Solution:
T Min<T>( T a, T b ) where T : IComparable<T> {
if (a.CompareTo( b ) < 0) return a;
else return b;
}
2. C# 2.0 Revisited Delegates
A delegate is a class that encapsulates one or more method. Internally, one delegate stores a list of method pointers, each of
which can be paired with a reference to an instance of the class containing an instance method.
A delegate can be declared as,
delegate void SimpleDelegate(); delegate int ReturnValueDelegate();
delegate void TwoParamsDelegate( string name, int age );
In C# 1.X Delegates were instantiated as,
public class DemoDelegate { void MethodA() { }
int MethodB() { }
void MethodC( string x, int y ) { }
void CreateInstance() {
SimpleDelegate a = new SimpleDelegate( MethodA ); ReturnValueDelegate b = new ReturnValueDelegate ( MethodB );
TwoParamsDelegate c = new TwoParamsDelegate(
MethodC ); // } }
Delegate instantiation in C# 2.0 ,
public class DemoDelegate
{
void MethodA() { }
int MethodB() { }
void MethodC( string x, int y ) { }
void CreateInstance() {
SimpleDelegate a = MethodA;
ReturnValueDelegate b = MethodB;
TwoParamsDelegate c = MethodC; //
}
// }
3. C# 2.0 Revisited Anonymous Methods
Using an anonymous method :
public class DemoDelegate {
void Repeat10Times( SimpleDelegate someWork )
{ for (int i = 0; i < 10; i++) someWork(); }
void Run2() {
int counter = 0;
this.Repeat10Times( delegate { Console.WriteLine("C# chapter" );
counter++; } );
Console.WriteLine( counter ); } // }
Parameters for an anonymous method :
public class DemoDelegate {
void Repeat10Times( TwoParamsDelegate callback )
{ for (int i = 0; i < 10; i++)
callback( "Linq book", i ); }
void Run3() { Repeat10Times(
delegate( string text, int age )
{ Console.WriteLine( "{0} {1}", text, age ); } );
}
// }
4. C# 2.0 Revisited Enumerators and Yield
a. IEnumerator and IEnumerable declarations:
yield return 4;
yield return 3;
yield return 2;
yield return 1;
yield return 0;
}
}
c. Enumeration using yield (typed):
public class CountdownYieldTypeSafe : IEnumerable<int> {
public int StartCountdown;
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
public IEnumerator<int> GetEnumerator() {
for (int i = StartCountdown - 1; i >= 0; i--)
{ yield return i; }
}
}
5. C# 3.0 Features Local Type Inference
C# 3.0 offers type inference that allows us to define a variable by using the var keyword instead of a specific type.This might
seem to be equivalent to defining a variable of type object, but it is not
var a = 2; //a is declared as int
object b = 2; // Boxing an int into an object
class VarDemo {
// invalid token 'var' in class, struct or interface member declaration
var k =0;
// type expected in parameter list
public void InvalidUseParameter( var x ){} // type expected in result type declaration
public var InvalidUseResult() { return 2; }
public void InvalidUseLocal() {
var x; // Syntax error, '=' expected
var y = null; // Cannot infer local variable type from 'null'
}
// }
Some lambda expressions have a particular name based on their purpose.A predicate is a Boolean expression that is intended to
indicate membership of an element in a group. For example, it is used to define how to filter items inside a loop:
// Predicate
age ) => age > 21
A projection is an expression that returns a type different from the type of its single parameter:
// Projection: takes a string and returns an int
( s ) => s.Length
Lambda expression as a predicate :
public static void Demo() {
string[] names = { "Marco", "Paolo", "Tom" }; Display( names, s => s.Length > 4 ); }
public static void Display<T>( T[] names, Func<T, bool> filter ){
foreach( T s in names) {
if (filter( s )) Console.WriteLine( s ); }
}
A lambda expression can also be assigned to a variable of these delegate types:
An extension method is not automatically considered. Its resolution follows some rules.
Here is the order of evaluation used to resolve a method for an identifier:
public static void Display<T>( this T[] names, Func<T, bool> filter ) {}
public static void Demo() {
string[] names = { "Marco", "Paolo", "Tom" };
names.Display( s => s.Length > 4 );// It was: Display( names, s => s.Length > 4 );
}
8. C# 3.0 Features Object Initialization Expressions
C# 3.0 introduces a shorter form of object initialization syntax that generates functionally equivalent code:
// Implicitly calls default constructor before object initialization
Customer customer = new Customer { Name = "Marco", Country = "Italy" };
a. Explicit constructor call in object initializer :
// Explicitly specify constructor to call before object initialization
Customer c1 = new Customer() { Name = "Marco", Country = "Italy" };
// Explicitly specify nondefault constructor
Customer c2 = new Customer( "Paolo", 21 ) { Country = "Italy" };
b. Nested object initializers :
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; }
}
}
public class Rectangle
{
private Point tl, br;
public Point TL
{
get { return tl; }
set { tl = value; }
}
public Point BR
{
get { return br; }
set { br = value; }
}
}
// Possible code inside a method
Rectangle r = new Rectangle { TL = new Point { X = 0, Y = 1 },BR = new Point { X = 2, Y = 3 } };
<>f__AnonymousType0`2[System.String,System.Int32] c5 is
<>f__AnonymousType5`2[System.String,System.String] c6 is
<>f__AnonymousTypea`2[System.String,System.String]
10. C# 3.0 Features Query Expressions
C# 3.0 also introduces query expressions, which have a syntax similar to the SQL language and are used to manipulate
data.This syntax is converted into regular C# 3.0 syntax that makes use of specific classes, methods, and interfaces that are part of the
LINQ libraries.
XVI.
The following code shows a prototype of the full syntax of a LINQ query expression:
query-expression ::=
from-clause query-body query-body
::= join-clause* (from-clause join-clause* | let-clause | where-clause)*
orderby-clause? (select-clause | groupby-clause) query-continuation?
from-clause ::= from itemName in srcExpr select-clause ::= select selExpr groupby-clause ::= group selExpr by keyExpr
The first from clause can be followed by zero or more from, let, or where clauses.
A let clause applies a name to the result of an expression, while a where clause defines a filter that will be applied to include specific
items in the results. Each from clause is a generator that represents an iteration over a sequence on which query operators (such as
the extension methods of System.Linq.Enumerable) are applied.
let-clause ::= let itemName = selExpr where-clause ::= where predExpr
A from clause can be followed by any number of join clauses. The final select or group clause can be preceded by an orderby clause
that applies an ordering
to the results:
join-clause ::= join itemName in srcExpr on keyExpr equals keyExpr (into itemName)?
orderby-clause ::= orderby (keyExpr (ascending | descending)?)* query-continuation ::= into itemName query-body.
XVII.
Conclusion:
Long post, I guess we covered a lot of concepts deeply. You can learn more theory from MSDN or other renowned community
sites. We covered very important and deep concepts of LINQ, C#2.0 and C# 3.0.
Happy Coding .
Original content of this article: http://language-integrated-query.com/Linq_CSharp_3.0_Features.aspx
To read more informative articles on C#, Asp.Net and MVC, follow A Practical Approach