www.midnightbeach.com
Download
Report
Transcript www.midnightbeach.com
Jon Shemitz
Complicated stuff, quickly.
.NET 2.0
.NET 2.0
●
Generics
50%
& Nullable Types
●
Iterators
10%
●
Delegate Enhancements
●
Partial Types
35%
5%
Generics
●
Collections before generics
●
Open classes
●
Open methods
●
Collections after generics
●
Nullable types
Collections before generics
Universal collections are pretty nice:
–
An ArrayList is a 1-D list of any object
–
A Hashtable can associate any object with any object
But we get an object back:
Always have to cast back to the type we put in.
Cumbersome, and boxing is not free.
Open Classes
Old style classes are now closed classes.
Open classes have type parameters.
A list of names in < > brackets
between class name and {} code.
List<T>{} and Dictionary<K, V>{}.
A List<string> is a closed constructed class.
Open Class Example
public static class Unique<T> where T : class, new()
{
private static T cache = default(T);
private static object cacheLock = new object();
// can't lock cache field (which may be null) // mustn't lock typeof(T) or typeof(Unique<T>)
public static T Instance
{
get
{
lock (cacheLock)
if (cache == null)
return cache = new T();
else
return cache;
}
}
}
// can't new string()
Open Methods
Only an open class can have:
A parameterized field, or a parameterized property,
Or a normal method,
with parameterized parameters or result
Any class can have an open method:
T ToType<T>(string AsString)
string ToString<T>(T value)
Collections after generics
A List<T> compiles to generic CIL
Same as Unique<T>
Yes, whatever the source language.
C#, Visual Fred, Delphi ...
The Add method only takes a T
List<string> can't Add(int)
The Get methods return a T - never has to be cast.
No runtime type checking - No boxing and unboxing
Nullable Types
●
bool? is the same as Nullable<bool>.
bool? ThreeWay = true; // also false and null
●
bool? is not the same as bool.
Can't do bool TwoWay = ThreeWay;
Have to do bool TwoWay = (bool) ThreeWay;
●
Can compare a nullable type to null
It's an error to read Value when == null.
That includes casting to base type.
Nullable types add null
●
An unset value that you can test inline.
Don't have to declare special flag value in each enum.
To test float point NAN, have to call double.IsNaN().
●
Reference types can already be null
Can't have string? or any other nullable reference type
●
C# hoists operators so they work with null
Only calls operators with non-null values
●
Boxing behavior
That's It For Generics
Any Quick Questions?
Iterators
IEnumerable and IEnumerator
Tiny little nested objects
Easy to enumerate linear list
Nested structures take state machines
That is, complicated and fragile
Iterators compile yield return code to a state machine.
Even recursive code!
Iterator example
public IEnumerator<FileSystemInfo> GetEnumerator()
{
foreach (FileSystemInfo Info in Unsorted(Root))
yield return Info;
}
private IEnumerable<FileSystemInfo> Unsorted(DirectoryInfo Path)
{
foreach (FileSystemInfo Info in Path.GetFileSystemInfos())
{
yield return Info;
DirectoryInfo Directory = Info as DirectoryInfo;
if (Directory != null)
foreach (FileSystemInfo Child in Unsorted(Directory))
yield return Child;
}
}
Simple delegate enhancements
●
Speed
Interface was 250% faster than delegate in 1.x
Delegates are ca 5% faster than interfaces in 2.x
●
New method group syntax
DelegateType DelegateInstance = Instance.Method;
Don't have to say new DelegateType()
Just like Delphi ...
Instance.Method specifies an overload method group
Valid delegate if one and only one overload in group
Advanced delegates
●
Anonymous Methods
●
Covariance and Contravariance
●
Call delegates asynchronously
Think of them as asynch primitives
What's Wrong With Named Methods?
●
●
In C# 1.0, delegates always refer to normal,
named methods
Three problems:
Clutter and bloat.
● No tie between callback and caller.
● Boilerplate - copying local variables to tiny
state objects to support callbacks &c.
●
Anonymous Methods
●
That is
–
●
Defining a method just so that you can create a delegate to
it makes your code harder to write and harder to read.
So
–
C# 2.0 supports anonymous methods, which let you create
a delegate to a special statement block, within a method.
Delegate expressions
●
delegate (optional parameters) {}
●
Valid in delegate expressions
–
In assignment
DelegateType DelegateInstance = delegate(int N) {};
// note the ; after the }
–
As a parameter to a method
Fn(delegate {})
–
Event list editing
SomeEvent += delegate(object sender, EventArgs E) {};
Capture
●
●
Anonymous methods can capture parameters and/or local
variables
Captured variables are implemented as fields in a singleton
instance of a Compiler Generated Class.
Captured parameters are copied in, by method
prolog, then only referred to as CGC fields.
●
Captured variables last as long as the delegate lasts.
●
Anonymous methods are named methods of the CGC.
Covariance
class Base
{
public static Derived BaseFn(Base B) { return new Derived(); }
}
class Derived : Base {}
delegate Base BaseFunction(Base B);
●
In 1.x, can’t say
BaseFunction F = new BaseFunction(Base.BaseFn)
A BaseFunction returns a Base instance
Base.BaseFn returns a Derived instance.
●
Can, in 2.x
Every Derived instance is also a Base instance
Contravariance
class Base
{
public static void BaseProc(Base B) { }
}
class Derived : Base
{
public static void DerivedProc(Derived D) { }
}
delegate void BaseMethod(Base B);
delegate void DerivedMethod(Derived D);
A method that takes a base type is compatible with
a delegate that takes a derived type:
●
DerivedMethod BaseD = new DerivedMethod(Base.BaseProc);
Complicated Names
●
●
●
Practical effect is that matching is looser.
You'll probably only notice covariance and
contravariance when 2.0 code won't compile
under 1.x, “even though it's not using generics”
Don't put effort into telling them apart, or even
remembering details of how matching is looser
Asynchronous Calls
●
Available in 1.0
●
Call any delegate via .BeginInvoke()
Runs in ThreadPool thread.
●
Collect results with .EndInvoke()
Do something while waiting for disk IO.
Get ready for the multicore future.
Less overhead than creating new Thread.
Less os work, and less user code
Asynchronous Example
public class ThreadEach<T>
{
public delegate void Processor(T Datum);
public static void Process(Processor P, IEnumerable<T> Data)
{
//foreach (T Datum in Data)
// P(Datum); // Process each Datum in the current thread
List<IAsyncResult> AsyncResults = new List<IAsyncResult>();
// Process each Datum in its own thread
foreach (T Datum in Data)
AsyncResults.Add(P.BeginInvoke(Datum, null, null));
// Wait for all threads to finish
foreach (IAsyncResult Async in AsyncResults)
P.EndInvoke(Async);
}
}
Partial Types
partial class Fred { protected int This; }
partial class Fred{ protected int That; }
–
Only one definition needs to have an access modifier
like public or internal
●
●
–
Multiple access modifiers, must all agree.
Can’t have public partial class Partial {} and internal partial
class Partial {}!
Similarly, only needs one base class
●
Multiple base classes, all must agree.
Thank you
Any Questions?
Midnight Beach
Contracting
Consulting
Training
Jon Shemitz
Talks fast.
Codes fast, too.