DEV321 Visual C# 2005: Language Enhancements Anders Hejlsberg Distinguished Engineer Microsoft Corporation C# Language Enhancements Generics Anonymous methods Nullable types Iterators Partial types and many more… 100% backwards compatible.

Download Report

Transcript DEV321 Visual C# 2005: Language Enhancements Anders Hejlsberg Distinguished Engineer Microsoft Corporation C# Language Enhancements Generics Anonymous methods Nullable types Iterators Partial types and many more… 100% backwards compatible.

DEV321
Visual C# 2005:
Language Enhancements
Anders Hejlsberg
Distinguished Engineer
Microsoft Corporation
C# Language Enhancements
Generics
Anonymous methods
Nullable types
Iterators
Partial types
and many more…
100% backwards compatible
Generics
public class List<T>
List
{
private T[]
object[]
elements;
elements;
private int count;
public void Add(T
Add(object
element)
element)
{
{
if (count == elements.Length) Resize(count * 2);
elements[count++] = element;
}
public T
object
this[int
this[int
index]
index]
{
{
get { return elements[index]; }
set { elements[index] = value; }
}
}
public int Count {
List
intList
intList
= }new=List();
new List<int>();
get { List<int>
return
count;
}
intList.Add(1);
// No
Argument
boxingis boxed
intList.Add(2);
// No
Argument
boxingis boxed
intList.Add("Three");
// Compile-time
Should be an error
int i = intList[0];
(int)intList[0];
//
// Cast
No cast
required
required
Generics
Why generics?
Type checking, no boxing, no downcasts
Reduced code bloat (typed collections)
How are C# generics implemented?
Instantiated at run-time, not compile-time
Checked at declaration, not instantiation
Work for both reference and value types
Complete run-time type information
Generics
Type parameters can be applied to
Class, struct, interface, delegate types
class Dictionary<K,V> {...}
struct HashBucket<K,V> {...}
interface IComparer<T> {...}
delegate R Function<A,R>(A arg);
Dictionary<string,Customer> customerLookupTable;
Dictionary<string,List<Order>> orderLookupTable;
Dictionary<string,int> wordCount;
Generics
Type parameters can be applied to
Class, struct, interface, delegate types
Methods
class Utils
{
public static T[] CreateArray<T>(int size) {
return new T[size];
}
}
public static void SortArray<T>(T[] array) {
...
}
string[] names = Utils.CreateArray<string>(10);
names[0] = "Jones";
...
Utils.SortArray(names);
Generics
Type parameters can be applied to
Class, struct, interface, delegate types
Methods
Type parameters can have constraints
class Dictionary<K,V>:
Dictionary<K,V> where
IDictionary<K,V>
K: IComparable
{ where K: IComparable<K>
publicV:
where
void
IKeyProvider<K>,
Add(K key, V value)
IPersistable,
{
new()
{
...
public
if (key.CompareTo(x)
(((IComparable)key).CompareTo(x)
void Add(K key, V==
value)
0) {...}
{
== 0) {...}
...
}
}
Generics
Zero or one primary constraint
Actual class, class, or struct
Zero or more secondary constraints
Interface or type parameter
Zero or one constructor constraint
new()
class Link<T> where T: class {...}
class Nullable<T> where T: struct {...}
class Relation<T,U> where T: class where U: T {...}
Generics
List<T>
Dictionary<K,V>
SortedDictionary<K,V>
Stack<T>
Queue<T>
Collection classes
Collection interfaces
Collection base classes
Utility classes
Reflection
IList<T>
IDictionary<K,V>
ICollection<T>
IEnumerable<T>
IEnumerator<T>
IComparable<T>
IComparer<T>
Collection<T>
KeyedCollection<T>
ReadOnlyCollection<T>
Nullable<T>
EventHandler<T>
Comparer<T>
Anonymous Methods
class MyForm : Form
{
ListBox listBox;
TextBox textBox;
Button addButton;
}
}
public MyForm() {
listBox = new ListBox(...);
textBox = new TextBox(...);
addButton = new Button(...);
addButton.Click += delegate
new EventHandler(AddClick);
{
}
listBox.Items.Add(textBox.Text);
};
void AddClick(object sender, EventArgs e) {
}
listBox.Items.Add(textBox.Text);
}
Anonymous Methods
Allows code block in place of delegate
Delegate type automatically inferred
Code block can be parameterless
Or code block can have parameters
In either case, return types must match
button.Click += delegate { MessageBox.Show("Hello"); };
button.Click += delegate(object sender, EventArgs e) {
MessageBox.Show(((Button)sender).Text);
};
Anonymous Methods
Code block can access local variables
public class Bank
public
{ class Bank
{
List<Account> GetLargeAccounts(double minBalance) {
List<Account>
accounts;
delegate boolHelper
Predicate<T>(T
item);
helper
= new
Helper();
helper.minBalance = minBalance;
GetOverdrawnAccounts() {
public List<Account>
class return
List<T>accounts.FindAll(helper.Matches);
return
accounts.FindAll(delegate(Account a) {
{
}
returnFindAll(Predicate<T>
a.Balance < 0;
public List<T>
filter) {
});
List<T>
result
= new
List<T>();
internal
class
Helper
}
foreach
(T item in this) {
{
if (filter(item))
result.Add(item);
internal double
minBalance;
List<Account> GetLargeAccounts(double minBalance) {
}
return
accounts.FindAll(delegate(Account
a) {
return
result;
internal
bool Matches(Account a) {
return
a.Balance
>= >=
minBalance;
}
return
a.Balance
minBalance;
}); }
}
}
}
}
}
Anonymous Methods
Method group conversions
Delegate type inferred when possible
using System;
using System.Threading;
class Program
{
static void Work() {...}
static void Main() {
Thread t = new Thread(Work);
Thread(new ThreadStart(Work));
t.Start();
}
}
Generics Performance
Nullable Types
System.Nullable<T>
Provides nullability for any value type
Struct that combines a T and a bool
public struct Nullable<T> where T: struct
{
public Nullable(T value) {...}
public T Value { get {...} }
public bool HasValue { get {...} }
...
}
Nullable<int> x = new Nullable<int>(123);
...
if (x.HasValue) Console.WriteLine(x.Value);
Nullable Types
T? same as System.Nullable<T>
int? x = 123;
double? y = 1.25;
null literal conversions
int? x = null;
double? y = null;
Nullable conversions
int i = 123;
int? x = i;
double? y = x;
int? z = (int?)y;
int j = (int)z;
//
//
//
//
int --> int?
int? --> double?
double? --> int?
int? --> int
Nullable Types
Lifted conversions and operators
int? x = GetNullableInt();
int? y = GetNullableInt();
int? z = x + y;
Comparison operators
int? x = GetNullableInt();
if (x == null) Console.WriteLine("x is null");
if (x < 0) Console.WriteLine("x less than zero");
Null coalescing operator
int? x = GetNullableInt();
int i = x ?? 0;
Iterators
foreach relies on “enumerator pattern”
GetEnumerator() method
foreach (object obj in list) {
DoSomething(obj);
}
Enumerator e = list.GetEnumerator();
while (e.MoveNext()) {
object obj = e.Current;
DoSomething(obj);
}
foreach makes enumerating easy
But enumerators are hard to write!
Iterators
public class ListEnumerator : IEnumerator
{
List list;
int index;
public class List
{
internal object[] elements;
internal int count; internal ListEnumerator(List list) {
this.list = list;
index = -1; {
public IEnumerator GetEnumerator()
}
return new ListEnumerator(this);
}
}
public bool MoveNext() {
public class List int i = index + 1;
{
if (i >= list.count) return false;
internal object[]
elements;
index
= i;
internal int count;
return true;
}
public IEnumerator GetEnumerator() {
for (int ipublic
= 0; iobject
< count;
i++) {{
Current
yield return
get elements[i];
{ return list.elements[index]; }
}
}
}
}
}
Iterators
public IEnumerator GetEnumerator() {
return new __Enumerator(this);
}
private class __Enumerator : IEnumerator
{
object current;
int state;
Method that incrementally computes
and returns a sequence of values
public bool MoveNext() {
switch (state) {
case 0:
current = "Hello";
state = 1;
return true;
case 1:
public class Test
current = "World";
{
state = 2;
public IEnumerator GetEnumerator()
{
return
true;
yield return "Hello";
default:
yield return "World";
return false;
}
}
}
}
yield return and yield break
Must return IEnumerator or IEnumerable
public object Current {
get { return current; }
}
}
Iterators
public class List<T>
{
public IEnumerator<T> GetEnumerator() {
for (int i = 0; i < count; i++)
yield return elements[i];
}
public IEnumerable<T> Descending() {
for (int i = count - 1; i >= 0; i--)
yield return elements[i];
}
public IEnumerable<T> Subrange(int index, int n) {
for (int i = 0; i < n; i++)
yield return elements[index + i];
}
}
List<Item> items =
foreach (Item x in
foreach (Item x in
foreach (Item x in
GetItemList();
items) {...}
items.Descending()) {...}
Items.Subrange(10, 20)) {...}
Partial Types
public partial class Customer
{
private int id; public class Customer
private string name;
{
private string address;
private int id;
private List<Orders>
orders;
private
string name;
}
private string address;
private List<Orders> orders;
public void SubmitOrder(Order order) {
public partial class Customer
orders.Add(order);
{
}
public void SubmitOrder(Order order) {
orders.Add(order);
public bool HasOutstandingOrders() {
}
return orders.Count > 0;
}
public bool HasOutstandingOrders()
{
}
return orders.Count > 0;
}
}
Static Classes
Only static members
Cannot be used as type of variable,
parameter, field, property, …
Examples include System.Console,
System.Environment
public static class Math
{
public static double Sin(double x) {...}
public static double Cos(double x) {...}
...
}
Property Accessors
Different accessor accessibility
One accessor can be restricted further
Typically set {…} more restricted
public class Customer
{
private string id;
public string CustomerId {
get { return id; }
internal set { id = value; }
}
}
External Aliases
Enables use of identically named types
in different assemblies
namespace Stuff
foo.dll
extern alias Foo;
{
extern
alias Bar;
public class
Utils
{
public class
staticProgram
void F() {...}
{
}
static void Main() {
}
Foo.Stuff.Utils.F();
Bar.Stuff.Utils.F();
}
namespace Stuff
bar.dll
}
{
public
class/r:Foo=foo.dll
Utils
C:\>csc
/r:Bar=bar.dll test.cs
{
public static void F() {...}
}
}
Namespace Alias Qualifiers
Enables more version resilient code
A::B looks up A only as alias
global::X looks up in global namespace
using IO = System.IO;
class Program
{
static void Main() {
IO::Stream s = new IO::File.OpenRead("foo.txt");
global::System.Console.WriteLine("Hello");
}
}
Inline Warning Control
#pragma warning
using System;
class Program
{
[Obsolete]
static void Foo() {}
static void Main() {
#pragma warning disable 612
Foo();
#pragma warning restore 612
}
}
Fixed Size Buffers
C style arrays in unsafe code
public struct OFSTRUCT
{
public byte cBytes;
public byte fFixedDisk;
public short nErrCode;
private int Reserved;
public fixed char szPathName[128];
}
Want to know more?
http://msdn.microsoft.com/vcsharp/language
Book Signing
Wednesday
12:30 – 1:30
Cabana Session
Wednesday
2:00 – 3:15
Cabana 5
Please fill out a session evaluation on CommNet
Q1: Overall satisfaction with the session
Q2: Usefulness of the information
Q3: Presenter’s knowledge of the subject
Q4: Presenter’s presentation skills
Q5: Effectiveness of the presentation
© 2004 Microsoft Corporation. All rights reserved.
This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.