C# 3.0 & LINQ Raimond Brookman – IT Architect
Outline -Linq Project -DLinq -XLinq -C# 3.0 Language Enhancements
Problem: Data != Objects
Service based Solution Customer Mgt Service (HTTP + XML) WebApplication Order Mgt WS Order Processing WS ORM Xml R/W Databound grid BR Check Transform Msg XML Config Xml Read
The LINQ Project Standard Query Operators Objects DLinq (ADO.NET) XLinq(System.Xml) XML.NET Language Integrated Query C# 3.0 VB 9.0 Others… SQLWinFS
Service based Solution with LINQ Customer Mgt Service (HTTP + XML) WebApplication Order Mgt WS Order Processing WS ORM Xml R/W Databound grid BR Check Transform Msg XML Config Xml Read DLINQ O-LINQ XLINQ O-LINQ
LINQ Style programming var contacts = from c in customers from c in customers where c.State == "WA" where c.State == "WA" select new { c.Name, c.Phone }; select new { c.Name, c.Phone }; class Contact { … }; List contacts = new List (); foreach(Customer c in customers) { if(c.State == “WA”) { Contact ct = new Contact(); Contact ct = new Contact(); ct.Name = c.Name; ct.Name = c.Name; ct.Phone = c.Phone; ct.Phone = c.Phone; contacts.Add(ct); contacts.Add(ct);}}
Query Expressions Language integrated query syntax from id in source { from id in source | where condition } [ orderby ordering, ordering, … ] select expr | group expr by key [ into id query ]
Standard Query Operators RestrictionWhere Projection Select, SelectMany Ordering OrderBy, ThenBy GroupingGroupBy Quantifiers Any, All Partitioning Take, Skip, TakeWhile, SkipWhile Sets Distinct, Union, Intersect, Except Elements First, FirstOrDefault, ElementAt Aggregation Count, Sum, Min, Max, Average Conversion ToArray, ToList, ToDictionary CastingOfType<T>
DLinq For Relational Data SqlConnection c = new SqlConnection(…); c.Open(); SqlCommand cmd = new c.Name, c.Name, c.Phone FROM Customers c FROM Customers c WHERE c.City WHERE c.City "London“); DataReader dr = c.Execute(cmd); while (dr.Read()) { string name = dr.GetString(0); string name = dr.GetString(0); string phone = dr.GetString(1); string phone = dr.GetString(1); DateTime date = dr.GetDateTime(2); DateTime date = dr.GetDateTime(2);}dr.Close(); Accessing data today Queries in quotes Loosely bound arguments Loosely typed result sets No compile time checks
public class Customer { … } public class Northwind: DataContext { public Table Customers; public Table Customers; …} Northwind db = new Northwind(…); var contacts = from c in db.Customers from c in db.Customers where c.City == "London" where c.City == "London" select new { c.Name, c.Phone }; select new { c.Name, c.Phone }; DLinq For Relational Data Accessing data with DLinq Classes describe data Strongly typed connection Integrated query syntax Strongly typed results Tables are like collections
DLinq For Relational Data Language integrated data access Maps tables and rows to classes and objects Builds on ADO.NET and.NET Transactions Mapping Encoded in attributes Relationships map to properties Persistence Automatic change tracking Updates through SQL or stored procedures
XLinq For XML Data XmlDocument doc = new XmlDocument(); XmlElement contacts = doc.CreateElement("contacts"); foreach (Customer c in customers) if (c.Country == "USA") { if (c.Country == "USA") { XmlElement e = doc.CreateElement("contact"); XmlElement e = doc.CreateElement("contact"); XmlElement name = doc.CreateElement("name"); XmlElement name = doc.CreateElement("name"); name.InnerText = c.CompanyName; name.InnerText = c.CompanyName; e.AppendChild(name); e.AppendChild(name); XmlElement phone = doc.CreateElement("phone"); XmlElement phone = doc.CreateElement("phone"); phone.InnerText = c.Phone; phone.InnerText = c.Phone; e.AppendChild(phone); e.AppendChild(phone); contacts.AppendChild(e); contacts.AppendChild(e); }doc.AppendChild(contacts); Programming XML today Great Lakes Food (503) … Imperativemodel Documentcentric No integrated queries Memoryintensive
XLinq For XML Data XElement contacts = new XElement("contacts", from c in customers from c in customers where c.Country == "USA" where c.Country == "USA" select new XElement("contact", select new XElement("contact", new XElement("name", c.CompanyName), new XElement("name", c.CompanyName), new XElement("phone", c.Phone) new XElement("phone", c.Phone) )); Programming XML with XLinq Declarativemodel Element centric Integratedqueries Smaller and faster
XLinq For XML Data Language integrated query for XML Expressive power of XPath / XQuery But with C# or VB as programming language Leverages experience with DOM Element centric, not document centric Functional construction Text nodes are just strings Simplified XML namespace support Faster and smaller
C# 3.0 Design Goals Integrate objects, relational, and XML Build on foundation laid in C# 1.0 and 2.0 Run on the.NET 2.0 CLR Remain 100% backwards compatible
C# 3.0 Language Innovations var contacts = from c in customers from c in customers where c.State == "WA" where c.State == "WA" select new { c.Name, c.Phone }; select new { c.Name, c.Phone }; var contacts = customers customers.Where(c => c.State == "WA").Where(c => c.State == "WA").Select(c => new { c.Name, c.Phone });.Select(c => new { c.Name, c.Phone }); Extensionmethods Lambdaexpressions Queryexpressions Objectinitializers Anonymoustypes Local variable type inference
Queries Through APIs public class List public class List { public List Where(Func predicate) { … } public List Where(Func predicate) { … } public List Select (Func selector) { … } public List Select (Func selector) { … } …} List customers = GetCustomerList(); List contacts = customers.Where(c => c.State == "WA").Select(c => c.Name); customers.Where(c => c.State == "WA").Select(c => c.Name); Query operators are just methods But what about other types? Declare operators in all collections? What about arrays? Methods compose to form queries
Queries Through APIs public static class Sequence { public static IEnumerable Where (IEnumerable source, public static IEnumerable Where (IEnumerable source, Func predicate) { … } Func predicate) { … } public static IEnumerable Select (IEnumerable source, public static IEnumerable Select (IEnumerable source, Func selector) { … } Func selector) { … } …} Customer[] customers = GetCustomerArray(); IEnumerable contacts = Sequence.Select( Sequence.Where(customers, c => c.State == "WA"), Sequence.Where(customers, c => c.State == "WA"), c => c.Name); c => c.Name); Query operators are static methods Huh? Want methods on IEnumerable<T>
namespace System.Query { public static class Sequence public static class Sequence { public static IEnumerable Where (this IEnumerable source, public static IEnumerable Where (this IEnumerable source, Func predicate) { … } Func predicate) { … } public static IEnumerable Select (this IEnumerable source, public static IEnumerable Select (this IEnumerable source, Func selector) { … } Func selector) { … } … }} Solution: Extension Methods using System.Query; Extension methods IEnumerable contacts = customers.Where(c => c.State == "WA").Select(c => c.Name); customers.Where(c => c.State == "WA").Select(c => c.Name); Brings extensions into scope obj.Foo(x, y) XXX.Foo(obj, x, y) IntelliSense!
Local Variable Type Inference int i = 5; string s = "Hello"; double d = 1.0; int[] numbers = new int[] {1, 2, 3}; Dictionary orders = new Dictionary (); var i = 5; var s = "Hello"; var d = 1.0; var numbers = new int[] {1, 2, 3}; var orders = new Dictionary (); “var” means same type as initializer
Anonymous Types public class Customer { public string Name; public string Name; public Address Address; public Address Address; public string Phone; public string Phone; public List Orders; public List Orders; …} public class Contact { public string Name; public string Name; public string Phone; public string Phone;} Customer c = GetCustomer(…); Contact x = new Contact { Name = c.Name, Phone = c.Phone }; Customer c = GetCustomer(…); var x = new { c.Name, c.Phone }; Customer c = GetCustomer(…); var x = new { Name = c.Name, Phone = c.Phone }; class ??? { public string Name; public string Name; public string Phone; public string Phone;} Projection style initializer
var contacts = from c in customers from c in customers where c.State == "WA" where c.State == "WA" select new { c.Name, c.Phone }; select new { c.Name, c.Phone }; Anonymous Types var contacts = customers. customers..Where(c => c.State == "WA“).Where(c => c.State == "WA“).Select(c => new { c.Name, c.Phone });.Select(c => new { c.Name, c.Phone }); class ??? { public string Name; public string Name; public string Phone; public string Phone;} IEnumerable<???> foreach (var c in contacts) { Console.WriteLine(c.Name); Console.WriteLine(c.Name); Console.WriteLine(c.Phone); Console.WriteLine(c.Phone);} ???
public delegate bool Predicate (T obj); public class List public class List { public List FindAll(Predicate test) { … } public List FindAll(Predicate test) { … } …} Lambda Expressions List customers = GetCustomerList(); List x = customers.FindAll( delegate(Customer c) { return c.State == "WA"; } delegate(Customer c) { return c.State == "WA"; }); List x = customers.FindAll(c => c.State == "WA"); Explicitly typed Statementcontext Implicitly typed Expressioncontext
Expression Trees public class Northwind: DataContext { public Table Customers; public Table Customers; public Table Orders; public Table Orders; …} Northwind db = new Northwind(…); var query = from c in db.Customers where c.State == "WA" select c; Northwind db = new Northwind(…); var query = db.Customers.Where(c => c.State == "WA"); How does this become SQL ? public class Table : IEnumerable public class Table : IEnumerable { public Table Where(Expression > predicate); public Table Where(Expression > predicate); …} Method asks for expression tree System.Expressions. Expression System.Expressions. Expression
Expression Trees Code as Data Func test = c => c.State == "WA"; Expression > test = c => c.State == "WA"; ParameterExpression c = Expression.Parameter(typeof(Customer), "c"); Expression.Parameter(typeof(Customer), "c"); Expression expr = Expression.EQ( Expression.EQ( Expression.Property(c, typeof(Customer).GetProperty("State")), Expression.Property(c, typeof(Customer).GetProperty("State")), Expression.Constant("WA") Expression.Constant("WA") ); ); Expression > test = Expression.Lambda >(expr, c); Expression.Lambda >(expr, c);
Expression Trees Code as Data Func test = c => c.State == "WA"; Expression > test = c => c.State == "WA"; ParameterExpression c = Expression.Parameter(typeof(Customer), "c"); Expression.Parameter(typeof(Customer), "c"); Expression expr = Expression.EQ( Expression.EQ( Expression.Property(c, typeof(Customer).GetProperty("State")), Expression.Property(c, typeof(Customer).GetProperty("State")), Expression.Constant("WA") Expression.Constant("WA") ); ); Expression > test = Expression.Lambda >(expr, c); Expression.Lambda >(expr, c);
Benefits Of LINQ Unified querying of objects, relational, XML Type checking and IntelliSense for queries SQL and XQuery-like power in C# and VB Extensibility model for languages / APIs
Call to Action -Get VS Download LINQ preview Play Around & See the power!
Q & A