© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
LINQ via C# 3.0
Chapter 2 – C# 3.0 Language Features
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
New C# 3.0 Language Features
•
Why more language features?
•
Increased developer productivity
–
Implicit typing, initializers, automatic properties,
anonymous types
•
Extensibility concepts
–
Extension methods, partial methods
•
Functional programming concepts
–
Lambda expressions, expression trees
•
Support for integrated queries (LINQ)
–
Language query operators
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Automatic Properties
public class Person {
private int id;
private string name;
public int Id {
get { return id; }
set { id = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
}
public class Person {
public string Name {
get; set;
}
public int Id {
get; set;
}
}
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Where’s The Magic?
•
Compiler generated code (from Reflector:
/>public class Person {
private int <Id>k__BackingField;
private string <Name>k__BackingField;
public int Id {
get { return this.<Id>k__BackingField; }
set { this.<Id>k__BackingField = value; }
}
public string Name {
get { return this.<Name>k__BackingField; }
set { this.<Name>k__BackingField = value; }
}
}
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
Read-only properties can be emulated by
specifying private set;
–
This is not the equivalent of a readonly field!
–
It can be modified from within the class
•
The backing field is inaccessible directly
•
Property logic cannot be customized for
one of the accessors
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Object Initializers
Person p = new Person(
2, “John Doe”);
//Or:
Person p =new Person();
p.Id = 2;
p.Name = “John Doe”;
Person p = new Person {
Id = 2,
Name = “John Doe”
};
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Where’s The Magic?
•
Compiler-generated code:
Person <>g__initLocal0 = new Person();
<>g__initLocal0.Id = 2;
<>g__initLocal0.Name = "John Doe";
Person p = <>g__initLocal0;
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
Non default constructors can be called
new Person(“John Doe”) { Id = 2 }
•
Why an excessive local variable?
–
Emulate atomic construction and assignment
–
Other threads can’t see a partially assigned object
•
Some properties have severe side effects
–
E.g., FileSystemWatcher.Enabled
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Collection Initializers
List<int> nums =
new List<int>();
nums.Add(5);
nums.Add(3);
nums.Add(20);
Dictionary<string,int> dict=
new Dictionary<string,int>();
dict.Add(“A”, 1);
dict.Add(“B”, 2);
List<int> nums =
new List<int> {
5, 3, 20
};
Dictionary<string,int> dict
= new Dictionary<string,int>
{
{ “A”, 1 },
{ “B”, 2 }
};
Becomes
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
What’s The Magic?
•
Compiler-generated code:
List<int> <>g__initLocal1 = new List<int>();
<>g__initLocal1.Add(5);
<>g__initLocal1.Add(3);
<>g__initLocal1.Add(20);
List<int> nums = <>g__initLocal1;
Dictionary<string, int> <>g__initLocal2 =
new Dictionary<string, int>();
<>g__initLocal2.Add("A", 1);
<>g__initLocal2.Add("B", 2);
Dictionary<string, int> dict = <>g__initLocal2;
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
The pattern works for any ICollection<T>
–
It calls Add(T) for each element
•
It also works for any IEnumerable that also
has an Add method
•
Performance: If you have a range
List<int> list = new List<int>(myEvenNums);
list.AddRange(myOddNums);
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Implicit Typing
•
Local variables can have an implicit type if
initialized within the declaration statement
int i = 5;
string s = “Hello”;
Employee e =
new Employee();
Dictionary<int,List<string>>
dict =
new
Dictionary<int,List<string>>();
var i = 5;
var s = “Hello”;
var e = new Employee();
var dict = new
Dictionary<string,List<string>>();
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Where’s The Magic?
•
Compiler generated code: (Boring…)
int i = 5;
string s = "Hello";
Employee e = new Employee();
Dictionary<int, List<string>> dict =
new Dictionary<int, List<string>>();
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
This is not Microsoft Visual Basic® 6 Dim
•
This is not VB6 Variant
•
This is not System.Object
•
The variable is strongly typed
–
But you don’t have to say the type
•
Variable must be initialized
–
null is not a valid initializer (what type?)
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
Adds confusion
–
This is not weak typing
•
using is a feasible alternative
using Dict = Dictionary<int, List<string>>;
Dict dict = new Dict();
•
Easy to abuse and difficult to understand
var x = a.DoIt(); //What does DoIt return?
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Review So Far
•
Developer productivity features
•
Automatic Properties – Cool, Useful
•
Object Initializers – Cool, Useful
•
Collection Initializers – Cool, Useful
•
Implicit Typing –
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Anonymous Types
•
Removes the burden of declaring “data-
holder” types
–
Narrows the Data Objects gap
class PayrollInfo {
public string Name;
public int Pay;
}
PayrollInfo pi =
new PayrollInfo();
pi.Name = “John”;
pi.Pay = CalcSalary();
var pi = new {
Name = “John”,
Pay = CalcSalary()
};
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Where’s The Magic?
•
Compiler-generated code (edited):
internal class __AnonymousType0<TName, TPay> {
private readonly TName __NameField;
private readonly TPay __PayField;
public __AnonymousType0(TName Name, TPay Pay) ...
public TName Name { get { return __NameField; } }
public TPay Pay { get { return __PayField; } }
public override string ToString() ...
public override bool Equals(object o) ...
public override int GetHashCode() ...
}
//Continued on the following slide
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Where’s The Magic?
//Continued from the previous slide
__AnonymousType0<string, int> pi =
new __AnonymousType0<string, int>(
“John”, CalcSalary());
•
ToString renders {Name = …, Pay = …}
–
There’s also a [DebuggerDisplay] attribute
•
The Equals and GetHashCode implementation
use EqualityComparer<T>.Default for each
field
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Anonymous From Existing
•
Anonymous types can be generated using
existing types’ properties:
Person person = ...;
var partialDetails = new {
person.Name, person.Age
};
//Equivalent to:
var partialDetails = new {
Name = person.Name, Age = person.Age
};
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
The generated type is immutable
–
Typical for data-holders, and thread-safe
•
The generated type is generic
–
The same generic type can be reused:
var x = new { Name = “A”, Pay = 15};
var y = new { Name = 5, Pay = 20};
•
Provides value semantics
–
Equals compares contents (like value types)
–
GetHashCode depends on contents (like value types)
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Feature Notes
•
That’s why we need implicit typing!
–
var is the only way to access the type
•
Passing anonymous types around is hard
–
Only through System.Object
–
Reflection can reveal properties:
object o = new { … };
foreach (PropertyInfo p in o.GetType()
.GetProperties()) {
Console.WriteLine(p.GetValue(o));
}
–
Reflection is expensive
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Review So Far
•
Developer productivity features
•
Automatic Properties
•
Object Initializers
•
Collection Initializers
•
Implicit Typing – Cool, Useful
•
Anonymous Types – Cool, Useful
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
Extension Methods
•
Challenges:
–
How do you add functionality to a sealed class?
–
How do you add functionality to an interface without
changing it or its implementors?
•
Static methods are the canonical solution
static int ToInt(string s) {
return int.Parse(s);
}
static int ToInt(this string s) {
return int.Parse(s);
}
Becomes
© Copyright SELA Software & Education Labs Ltd. 14-18 Baruch Hirsch St. Bnei Brak 51202 Israel
What’s The Difference?
•
Discoverability
–
IntelliSense® support
•
Natural (fluent) syntax
string s = ...;
float f = Util.ToFloat(s);
int j = Util.Round(f);
//Or:
string s = ...;
int j =
Util.Round(Util.ToFloat(s));
string s = ...;
int j = s.ToFloat().Round();
Becomes