Tải bản đầy đủ (.pptx) (56 trang)

Chapter 2 - CSharp 3.0 Language Features

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (836.41 KB, 56 trang )

© 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

×