C# 3.0 and .NET 3.5: A Brief Overview

38
CHARLES UNIVERSITY IN PRAGUE http://d3s.mff.cuni.cz faculty of mathematics and physics C# 3.0 and .NET 3.5: A Brief Overview Pavel Ježek

description

C# 3.0 and .NET 3.5: A Brief Overview. Pavel Je žek. C# 3.0 Features. Implicitly Typed Local Variables Extension Methods Lambda Expressions Object Initializers Collection Initializers Anonymous Types Expression Trees Query Expressions - PowerPoint PPT Presentation

Transcript of C# 3.0 and .NET 3.5: A Brief Overview

Page 1: C# 3.0 and .NET 3.5: A Brief Overview

CHARLES UNIVERSITY IN PRAGUE

http://d3s.mff.cuni.cz

faculty of mathematics and physics

C# 3.0 and .NET 3.5: A Brief Overview

Pavel Ježek

Page 2: C# 3.0 and .NET 3.5: A Brief Overview

C# 3.0 Features

Implicitly Typed Local VariablesExtension MethodsLambda ExpressionsObject InitializersCollection InitializersAnonymous TypesExpression TreesQuery Expressions

C# 3.0 compiler and .NET 3.5 libraries are part of Visual Studio 2008

Pavel JežekC# 3.0 and .NET 3.5

Page 3: C# 3.0 and .NET 3.5: A Brief Overview

Implicitly Typed Local Variables

Examples:var i = 5;var s = "Hello";var d = 1.0;var numbers = new int[] {1, 2, 3};var orders = new Dictionary<int,Order>();

Are equivalent to:int i = 5;string s = "Hello";double d = 1.0;int[] numbers = new int[] {1, 2, 3};Dictionary<int,Order> orders = new Dictionary<int,Order>();

Errors:var x; // Error, no initializer to infer type fromvar y = {1, 2, 3}; // Error, collection initializer not permittedvar z = null; // Error, null type not permitted

Pavel JežekC# 3.0 and .NET 3.5

Page 4: C# 3.0 and .NET 3.5: A Brief Overview

Extension Methods

Declaration:public static partial class Extensions {

public static int ToInt32(this string s) {return Int32.Parse(s);

}}

Usage:string s = "1234";

int i = s.ToInt32(); // Same as Extensions.ToInt32(s)

Instance methods take precedence over extension methodsExtension methods imported in inner namespace declarations take precedence over extension methods imported in outer namespace declarations

Pavel JežekC# 3.0 and .NET 3.5

Page 5: C# 3.0 and .NET 3.5: A Brief Overview

Extension Methods (2)

Declaration:public static partial class Extensions {

public static T[] Slice<T>(this T[] source, int index, int count) {

if (index < 0 || count < 0 || source.Length – index < count)

throw new ArgumentException();T[] result = new T[count];Array.Copy(source, index, result, 0, count);return result;

}}

Usage:int[] digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int[] a = digits.Slice(4, 3); // Same as Extensions.Slice(digits, 4, 3)

Pavel JežekC# 3.0 and .NET 3.5

Page 6: C# 3.0 and .NET 3.5: A Brief Overview

Lambda ExpressionsExample of C# 2.0 anonymous method:class Program {

delegate T BinaryOp<T>(T x, T y);

static void Method<T>(BinaryOp<T> op, T p1, T p2) {Console.WriteLine(op(p1, p2));

}

static void Main() {Method(delegate(int a, int b) { return a + b; }, 1,

2);}

}C# 3.0 lambda expressions provide further simplification:class Program {

delegate T BinaryOp<T>(T x, T y);

static void Method<T>(BinaryOp<T> op, T p1, T p2) {Console.WriteLine(op(p1, p2));

}

static void Main() {Method((a, b) => a + b, 1, 2);

} }

Pavel JežekC# 3.0 and .NET 3.5

Page 7: C# 3.0 and .NET 3.5: A Brief Overview

Lambda Expressions (2)

Expression or statement bodyImplicitly or explicitly typed parametersExamples:x => x + 1 // Implicitly typed, expression bodyx => { return x + 1; } // Implicitly typed, statement body(int x) => x + 1 // Explicitly typed, expression body(int x) => { return x + 1; } // Explicitly typed, statement body(x, y) => x * y // Multiple parameters() => Console.WriteLine() // No parameters

A lambda expression is a value, that does not have a type but can be implicitly converted to a compatible delegate type

delegate R Func<A,R>(A arg);Func<int,int> f1 = x => x + 1; // OkFunc<int,double> f2 = x => x + 1; // OkFunc<double,int> f3 = x => x + 1; // Error – double cannot be

// implicitly converted to int

Pavel JežekC# 3.0 and .NET 3.5

Page 8: C# 3.0 and .NET 3.5: A Brief Overview

Lambda Expressions (3)

Lambda expressions participate in inference process of type arguments of generic methodsIn initial phase, nothing is inferred from arguments that are lambda expressionsFollowing the initial phase, additional inferences are made from lambda expressions using an iterative process

Pavel JežekC# 3.0 and .NET 3.5

Page 9: C# 3.0 and .NET 3.5: A Brief Overview

Lambda Expressions (4)Generic extension method example:public class List<T> : IEnumerable<T>, … { … }public static class Sequence {

public static IEnumerable<S> Select<T,S>(this IEnumerable<T> source,Func<T, S> selector)

{foreach (T element in source) yield return

selector(element);}

}Calling extension method with lambda expression:List<Customer> customers = GetCustomerList();IEnumerable<string> names = customers.Select(c => c.Name);Rewriting extension method call:IEnumerable<string> names = Sequence.Select<T, S>(customers, c => c.Name);T type argument is inferred to Customer based on source argument typeSequence.Select<Customer, S>(customers, c => c.Name)c lambda expression argument type is infered to CustomerSequence.Select<Customer, S>(customers, (Customer c) => c.Name)S type argument is inferred to string based on return value type of the lambda expressionSequence.Select<Customer, string>(customers, (Customer c) => c.Name)

Pavel JežekC# 3.0 and .NET 3.5

Page 10: C# 3.0 and .NET 3.5: A Brief Overview

Lambda Expressions: Expression Trees

Permit lambda expressions to be represented as data structures instead of executable codeLambda expression convertible to delegate D (assignment causes code generation) is also convertible to expression tree (abstract syntax tree) of type System.Linq.Expressions.Expression<D> (assignment causes expression tree generation)Expression trees are immutable

IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret

LambdaExpression BinaryExpression BinaryExpression ParameterExpression(“value”) ConstantExpression(2) ConstantExpression(10)

Func<int, int> f = Expression<Func<int, int>> e =

value => (value + 2) * 1

Page 11: C# 3.0 and .NET 3.5: A Brief Overview

Object Initializers

Class representing a point: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; } }

}

New instance can be created using object initializer:var a = new Point { X = 0, Y = 1 };

Which is equivalent to:var a = new Point();a.X = 0;a.Y = 1;

Pavel JežekC# 3.0 and .NET 3.5

Page 12: C# 3.0 and .NET 3.5: A Brief Overview

Object Initializers (2)Class representing a rectangle:public class Rectangle {

private Point p1, p2;public Point P1 { get { return p1; } set { p1 = value; } }public Point P2 { get { return p2; } set { p2 = value; } }

}

New instance can be created using object initializer:var r = new Rectangle {

P1 = new Point { X = 0, Y = 1 },P2 = new Point { X = 2, Y = 3 }

};

Which is equivalent to:var r = new Rectangle();var __p1 = new Point();__p1.X = 0;__p1.Y = 1;r.P1 = __p1;var __p2 = new Point();__p2.X = 2;__p2.Y = 3;r.P2 = __p2;

Pavel JežekC# 3.0 and .NET 3.5

Page 13: C# 3.0 and .NET 3.5: A Brief Overview

Object Initializers (3)Class representing a rectangle with constructor that allocates p1 and p2:public class Rectangle {

private Point p1 = new Point();private Point p2 = new Point();public Point P1 { get { return p1; } }public Point P2 { get { return p2; } }

}

New instance can be created using object initializer:var r = new Rectangle {

P1 = { X = 0, Y = 1 },P2 = { X = 2, Y = 3 }

};

Which is equivalent to:var r = new Rectangle();r.P1.X = 0;r.P1.Y = 1;r.P2.X = 2;r.P2.Y = 3;

Pavel JežekC# 3.0 and .NET 3.5

Page 14: C# 3.0 and .NET 3.5: A Brief Overview

Collection Initializers

Example:List<int> digits = new List<int> { 0, 1, 2};

Is equivalent to:List<int> digits = new List<int>();digits.Add(0);digits.Add(1);digits.Add(2);

List<T> has to implement System.Collections.Generic.ICollection<T> interface with the Add(T) method

Pavel JežekC# 3.0 and .NET 3.5

Page 15: C# 3.0 and .NET 3.5: A Brief Overview

Combining Object and Collection Initializers

Class representing a contact with name and list of phone numbers:public class Contact {

private string name;private List<string> phoneNumbers = new List<string>();public string Name { get { return name; } set { name = value; } }public List<string> PhoneNumbers { get { return phoneNumbers; } }

}

List of contacts can be created and initialized with:var contacts = new List<Contact> {

new Contact {Name = "Chris Smith",PhoneNumbers = { "206-555-0101", "425-882-8080" }

},new Contact {

Name = "Bob Harris",PhoneNumbers = { "650-555-0199" }

}};

Which is equivalent to:var contacts = new List<Contact>();var __c1 = new Contact();__c1.Name = "Chris Smith";__c1.PhoneNumbers.Add("206-555-0101");__c1.PhoneNumbers.Add("425-882-8080");contacts.Add(__c1);var __c2 = new Contact();__c2.Name = "Bob Harris";__c2.PhoneNumbers.Add("650-555-0199");contacts.Add(__c2);

Pavel JežekC# 3.0 and .NET 3.5

Page 16: C# 3.0 and .NET 3.5: A Brief Overview

Auto-implemented Properties

Backed up by a private field normally inaccessible to programmer (only via the property):

class LightweightCustomer {public double TotalPurchases { get; set; }public string Name { get; private set; } // read-onlypublic int CustomerID { get; private set; } // read-only

}

Pavel JežekC# 3.0 and .NET 3.5

Page 17: C# 3.0 and .NET 3.5: A Brief Overview

Anonymous Types

Following expression:new { p1 = e1 , p2 = e2 , … pn = en }Can be used to define an anonymous type :class __Anonymous1 {

private T1 f1 ;private T2 f2 ;…private Tn fn ;

public T1 p1 { get { return f1 ; } set { f1 = value ; } }public T2 p2 { get { return f2 ; } set { f2 = value ; } }…public T1 p1 { get { return f1 ; } set { f1 = value ; } }

}And create its instance using object initializer

Different anonymous object initilizers that define properties with same names in the same order generate the same anonymous type:var p1 = new { Name = "Lawnmower", Price = 495.00 };var p2 = new { Name = "Shovel", Price = 26.95 };p1 = p2;

Pavel JežekC# 3.0 and .NET 3.5

Page 18: C# 3.0 and .NET 3.5: A Brief Overview

Partial Methods

Can appear only in partial classes or structs, and must be void, private and without out parameters:

partial class A {string _name;

partial void OnNameChanged();

public string Name {set {

_name = value;OnNameChanged();

}}

}

partial class A {partial void OnNameChanged() {

// Do something}

}

Pavel JežekC# 3.0 and .NET 3.5

Page 19: C# 3.0 and .NET 3.5: A Brief Overview

Query Expressions – Examples

Query expression:

from c in customers where c.City == "London“ select c

Gets translated to:

customers.Where(c => c.City == "London")

Pavel JežekC# 3.0 and .NET 3.5

Page 20: C# 3.0 and .NET 3.5: A Brief Overview

Query Expressions – Examples

Query expression:

from c in customers where c.City == "London“ select c.Name

Gets translated to:

customers.Where(c => c.City == "London").Select(c => c.Name)

Pavel JežekC# 3.0 and .NET 3.5

Page 21: C# 3.0 and .NET 3.5: A Brief Overview

Query Expressions – Examples

Query expression:

from c in customers orderby c.Name select new { c.Name, c.Phone }

Gets translated to:

customers.OrderBy(c => c.Name).Select(c => new { Name = c.Name, Phone = c.Phone })

Pavel JežekC# 3.0 and .NET 3.5

Page 22: C# 3.0 and .NET 3.5: A Brief Overview

Query Expressions – ExamplesQuery expression:

from c in customerswhere c.City == "London"from o in c.Orderswhere o.OrderDate.Year == 2005select new { c.Name, o.OrderID, o.Total }

Gets translated to:

customers.Where(c => c.City == "London").SelectMany(c =>

c.Orders.Where(o => o.OrderDate.Year == 2005).Select(o => new {

Name = c.Name, OrderID = o.OrderID, Total = o.Total }))

Pavel JežekC# 3.0 and .NET 3.5

Page 23: C# 3.0 and .NET 3.5: A Brief Overview

Query ExpressionsQuery expressions or LINQ (Language INtergrated Queries) are the key feature of .NET 3.5Query expressions are translated to method calls – works on classes like:

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

class C<T>{

public C<T> Where(Func<T,bool> predicate);public C<S> Select<S>(Func<T,S> selector);public C<S> SelectMany<S>(Func<T,C<S>> selector);public O<T> OrderBy<K>(Func<T,K> keyExpr);public O<T> OrderByDescending<K>(Func<T,K> keyExpr);public C<G<K,T>> GroupBy<K>(Func<T,K> keyExpr);public C<G<K,E>> GroupBy<K,E>(Func<T,K> keyExpr, Func<T,E>

elemExpr);}…

Pavel JežekC# 3.0 and .NET 3.5

Page 24: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Creating Entity Classes

Only instances of “entity classes”, i.e. “entities”, can be stored in/retrieved from databases

[Table] // Table is named “Customer”public class Customer{

public string CustomerID; // Transient data not stored in DBpublic string City; // Transient data not stored in DB

}

[Table(Name="Customers")]public class Customer{

public string CustomerID; // Transient data not stored in DBpublic string City; // Transient data not stored in DB

}

[Table(Name="Customers")]public class Customer{

[Column(Id=true)] // Part of database primary keypublic string CustomerID;[Column]public string City;

}

Pavel JežekC# 3.0 and .NET 3.5

Page 25: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL - DataContext

DataContext is equivalent of ADO.NET connectionIt retrieves data (objects) from the database and submits changesIt translates requests (queries) for objects into SQL queries

Using the DataContext to retrieve customer objects whose city is London: // DataContext takes a connection string DataContext db = new DataContext("c:\\northwind\\

northwnd.mdf");

// Get a typed table to run queriesTable<Customer> Customers = db.GetTable<Customer>();

// Query for customers from Londonvar q = from c in Customers where c.City == "London" select c;

foreach (var cust in q) {Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);

}

Pavel JežekC# 3.0 and .NET 3.5

Page 26: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Strongly Typed DataContext

public partial class Northwind : DataContext{

public Table<Customer> Customers;public Table<Order> Orders;public Northwind(string connection): base(connection) {}

}

Retrieving customer objects whose city is London more easily:

Northwind db = new Northwind("c:\\northwind\\northwnd.mdf");

var q = from c in db.Customers where c.City == "London“ select c;

foreach (var cust in q) {Console.WriteLine("id = {0}, City = {1}",cust.CustomerID, cust.City);

}

Pavel JežekC# 3.0 and .NET 3.5

Page 27: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Query Execution

Queries are not imperative – they are not executed immediately

var q = from c in db.Customerswhere c.City == "London"select c;

Only creates an instance of IQueryable<Customer> type and assigns it to qWhen the application tries to enumerate the contents of a query, it gets executed (i.e. deferred execution):

// Execute first timeforeach (Customer c in q) Console.WriteLine(c.CompanyName);

// Execute second timeforeach (Customer c in q) Console.WriteLine(c.CompanyName);

Pavel JežekC# 3.0 and .NET 3.5

Page 28: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Query Execution

Queries are not imperative – they are not executed immediately

var q = from c in db.Customerswhere c.City == "London"select c;

Only creates an instance of IQueryable<Customer> type and assigns it to qWhen the application tries to enumerate the contents of a query, it gets executed (i.e. deferred execution):

// Executedb.Log = Console.Out;

foreach (Customer c in q) Console.WriteLine(c.CompanyName);

Standard output:SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], [t0].

[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Extension], [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath]

FROM [dbo].[Employees] AS [t0]WHERE [t0].[City] = @p0-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]

Pavel JežekC# 3.0 and .NET 3.5

Page 29: C# 3.0 and .NET 3.5: A Brief Overview

Expression Trees

Permit lambda expressions to be represented as data structures instead of executable codeLambda expression convertible to delegate D (assignment causes code generation) is also convertible to expression tree (abstract syntax tree) of type System.Linq.Expressions.Expression<D> (assignment causes expression tree generation)Expression trees are immutable

Pavel JežekC# 3.0 and .NET 3.5

IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: add IL_0003: ldc.i4.s 10 IL_0005: mul IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret

LambdaExpression BinaryExpression BinaryExpression ParameterExpression(“value”) ConstantExpression(2) ConstantExpression(10)

Func<int, int> f = Expression<Func<int, int>> e =

value => (value + 2) * 1

Page 30: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Advantage of Deferred Execution

Partial query contruction:

var q = from c in db.Customerswhere c.City == "London"select c;

if (orderByLocation) {

q = from c in qorderby c.Country, c.Cityselect c;

} else if (orderByName) {

q = from c in qorderby c.ContactNameselect c;

}

foreach (Customer c in q) Console.WriteLine(c.CompanyName);

Pavel JežekC# 3.0 and .NET 3.5

Page 31: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Avoiding Deferred Execution

Query can be converted to standard collection classes using ToList() or ToArray() Standard Query Operators – leads to immediate execution:

var q = from c in db.Customerswhere c.City == "London"select c;

// Execute once using ToList(), ToArray()var list = q.ToList();

foreach (Customer c in list) Console.WriteLine(c.CompanyName);

foreach (Customer c in list) Console.WriteLine(c.CompanyName);

Pavel JežekC# 3.0 and .NET 3.5

Page 32: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Defining Relationships

[Table(Name="Customers")]public class Customer{

[Column(Id=true)]public string CustomerID;...private EntitySet<Order> _Orders;[Association(Storage="_Orders", OtherKey="CustomerID")]public EntitySet<Order> Orders {

get { return this._Orders; }set { this._Orders.Assign(value); }

}}

[Table(Name="Orders")]public class Order{

[Column(Id=true)]public int OrderID;[Column]public string CustomerID;

private EntityRef<Customer> _Customer;

[Association(Storage="_Customer", ThisKey="CustomerID")]public Customer Customer {

get { return this._Customer.Entity; }set { this._Customer.Entity = value; }

}}

Pavel JežekC# 3.0 and .NET 3.5

Page 33: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Querying Across Relationships

Query using the Orders property to form the cross product between customers and orders, producing a new sequence of Customer and Order pairs:

var q = from c in db.Customersfrom o in c.Orderswhere c.City == "London"select new { c, o };

Another query producing the same result:

var q = from o in db.Orderswhere o.Customer.City == "London"select new { c = o.Customer, o };

Pavel JežekC# 3.0 and .NET 3.5

Page 34: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Modifying Entities

Northwind db = new Northwind("c:\\northwind\\northwnd.mdf");

// Query for a specific customerstring id = "ALFKI";var cust = db.Customers.Single(c => c.CustomerID == id);

// Change the name of the contactcust.ContactName = "New Contact";

// Delete an existing OrderOrder ord0 = cust.Orders[0];

// Removing it from the table also removes it from the Customer’s listdb.Orders.Remove(ord0);

// Create and add a new Order to Orders collectionOrder ord = new Order { OrderDate = DateTime.Now };cust.Orders.InsertOnSubmit(ord);

// Ask the DataContext to save all the changes – generates appropriate SQL commanddb.SubmitChanges();

Pavel JežekC# 3.0 and .NET 3.5

Page 35: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Creating Simple Databases

[Table(Name="DVDTable")]public class DVD{

[Column(Id = true)]public string Title;[Column]public string Rating;

}

public class MyDVDs : DataContext{

public Table<DVD> DVDs;public MyDVDs(string connection) : base(connection) {}

}

// Creating a new database MyDVDs db = new MyDVDs("c:\\mydvds.mdf");db.CreateDatabase();

// Replacing an existing oneMyDVDs db = new MyDVDs("c:\\mydvds.mdf");

if (db.DatabaseExists()) {db.DeleteDatabase();

}

db.CreateDatabase();

Pavel JežekC# 3.0 and .NET 3.5

Page 36: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Inheritance

[Table][InheritanceMapping(Code = "C", Type = typeof(Car))][InheritanceMapping(Code = "T", Type = typeof(Truck))][InheritanceMapping(Code = "V", Type = typeof(Vehicle), IsDefault = true)]public class Vehicle {

[Column(IsDiscriminator = true)]public string Key;[Column(Id = true)]public string VIN;[Column]public string MfgPlant;

}

public class Car : Vehicle {[Column]public int TrimCode;[Column]public string ModelName;

}

public class Truck : Vehicle {[Column]public int Tonnage;[Column]public int Axles;

}

Pavel JežekC# 3.0 and .NET 3.5

Page 37: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Inheritance

Pavel JežekC# 3.0 and .NET 3.5

• Example queries:

var q = db.Vehicle.Where(p => p is Truck);

var q = db.Vehicle.OfType<Truck>();

var q = db.Vehicle.Select(p => p as Truck).Where(p => p != null);foreach (Truck p in q)

Console.WriteLine(p.Axles);

Page 38: C# 3.0 and .NET 3.5: A Brief Overview

LINQ to SQL – Query Visualizer in VS

static void Main(string[] args) {Northwnd db = new Northwnd(@"C:\program files\linq preview\data\northwnd.mdf");var q =

from c in db.Customerswhere c.City == "London"select c;

} // Breakpoint

Pavel JežekC# 3.0 and .NET 3.5