Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

34
Jon Shemitz Complicated stuff, quickly. Advanced Delegate s
  • date post

    30-Jan-2016
  • Category

    Documents

  • view

    222
  • download

    0

Transcript of Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Page 1: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Jon ShemitzComplicated stuff, quickly.

AdvancedDelegates

Page 2: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Advanced Delegates

Delegate syntax● Delegate Arcana 40%

Invocation lists, events, dynamic delegates

Delegates vs interfaces

Miscellaneous 2.0 enhancements● Anonymous Methods 15%

Delegates as thread primitives● Asynchronous Invoke 30%● The System Thread Pool 15%

Page 3: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Invocation Lists

● Delegate class manages an invocation list

Implementation changed from 1.1 to 2.0

Calling (invoking) a delegate is much faster in 2.0● Each invocation list is immutable

Operators like + and - return new lists

The static methods Delegate.Combine and Delegate.Remove

+= and -= work by replacement

Page 4: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Delegate Combining

● Value equality, not reference equality

You do not have to -= the delegate instance you added

Can += Instance.Method now and -= Instance.Method later

Yes, these are two separate delegate instances

● List length matters, on Delegate.Remove

Subtract Two from Two, and you have Zero

Subtract Four from Two, and you have Two● These rules apply to events, too

Page 5: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Event Syntax

Partial understanding of events is nearly universal!● Simple, field-like events have implicit methods.

An event is never a local variable.

Within its class, an event is a delegate -

Outside, an event is the implicit add and remove methods.

● Complex, property-like events have no fields.Explicit add and remove methods.

Only those two methods, even within class - not storage.

Page 6: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Create Delegate

Delegate.CreateDelegate

Pass a MethodInfo, or a method name

Fewer constraints in 2.0

Calling the delegate is faster than MethodInfo.Invoke

Good with dynamically generated methods

Getting dynamically loaded code by name is bad

Subject to collisions

Interface gets code by contract

Page 7: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

(Code By Contract)

Standard plug-in architecture:● Contract library, used by app and plug-ins● Contains your IPlugin interface● Loading plug-in does GetExportedTypes

Finds types assignment compatible with IPlugin Creates instance, and casts to IPlugin

Page 8: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Delegate Enhancements in 2.0

● New method group syntax

DelegateType DelegateInstance = Instance.Method;

Don't have to say new DelegateType(Instance.Method)

Just like Delphi ...

Instance.Method specifies an overload method group

Valid delegate if one and only one overload in group

● Speed

Interface was 2½ times faster than delegate in 1.x

Delegates are ca 5% faster than interfaces in 2.x

Page 9: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Choose on Semantics

Interface advantages

Contracts & dynamically loaded code.

● Interfaces are free from versioning issues and name collisions.

● You can control which methods implement the interface.

● An interface reference can give you access to a whole personality:

Other methods in interface, and other interfaces on object.

● Interfaces used to be faster than delegates. Same speed, in 2.0.

Delegate advantages

Callbacks & thread procs.

● Less code to create a delegate than to support an interface - especially when interface supported by a nested class.

● Class may offer a choice of delegate compatible methods; interface reference means the class must explicitly support the interface.

● You can create a delegate to a static or anonymous method. Interface methods are always named instance methods.

Page 10: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

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.xEvery Derived instance is also a Base instance.

Page 11: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

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);

Page 12: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

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

Just remember assignment compatibility

Page 13: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

That's it for the basics

Any questions?

Advanced DelegatesAnonymous Methods

Asynchronous callsDelegates are asynch primitives

Page 14: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

When a method isn't right

Is there something wrong with named methods?Until 2.0, delegates always referred to named methods.

Usually fine - but there are three problems:● Callbacks are hard to read.

They make you jump around. They add clutter and bloat.

● No tie between callback and caller.● Boilerplate - copying local variables to tiny state

objects to support callbacks &c.

Page 15: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Anonymous Methods

● Defining a method just so that you can create a delegate to it makes your code harder to write and harder to read.

● Part of a method has been hoisted into another method.● C# 2.0 supports anonymous methods, which let you create a

delegate to a special statement block, within a method.

● The compiler does the hoisting.● You can't call an anonymous method by mistake.● The compiler does capture better than you do.

(The next screen is about capture.)

Page 16: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

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 prologue, then only referred to as CGC fields.

● Captured variables last as long as the delegate lasts.

● Anonymous methods are named methods of the CGC.

Page 17: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Anonymous Method Syntax

● delegate (optional parametersparameters) {}An anonymous method never has a return type

● 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) {};

Page 18: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Asynchronous Calls

● You can run any delegate in a thread Available in 1.0 Most people don't know this Syntax is weird, so people “pass” and never return You have to add two null parameters to BeginInvoke

● Functional programmingEndInvoke is like Join, except it returns a typed result.

Delegates are asynch primitives:

Easiest way to pass parameters & get thread results.

Page 19: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Asynchronous Invoke

The best way to pass data to/from a thread

For example: read file to string

Start a read running

Do any other setup

EndInvoke when really need result

A cheap, functional threadTakes a string

Returns a string

May use ThreadPool directly if don't need result.

Page 20: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Runtime Methods

All delegates have runtime methods● Synchronous Invoke, in caller's thread● Asynchronous BeginInvoke, in ThreadPool thread

Returns IAsyncResult● EndInvoke takes that IAsyncResult

IAsyncResult contains a wait handle

Must always call EndInvoke

Page 21: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

EndInvoke

● BeginInvoke starts asynch call● Collect results with .EndInvoke()

Returns same type as delegate

Whether void or string or whateverCan use asynch invoke with void delegate to pass parameters -

Cheaper than creating anonymous method that captures parameters.

No casting!● Less overhead than creating new Thread

Less OS work, and less user code

Page 22: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Control.BeginInvoke

● Two different BeginInvoke methods

Both return IAsyncResult

Never confuse the two!● Delegate BeginInvoke runs in own thread

Must call EndInvoke● Control.BeginInvoke runs in control's thread

Can omit call to EndInvoke

Page 23: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

A Parallelizing Example

//foreach (T Datum in Data)// P(Datum); // Process each Datum in the current thread

public class ThreadEach<T>{ public delegate void Processor(T Datum);

public static void Process(Processor P, IEnumerable<T> Data) { 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); }}

Page 24: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

That was a bad example

What was wrong with that?● Not a good template

Each delegate has own parameter list● Too many threads!

Need to match thread count to processor count

Use a Semaphore so only one thread per processor

Each thread signs in and signs out

Page 25: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Those Two Nulls

● The 'extra' parameters to BeginInvoke

Don't have to be null● A delegate called after asynch delegate returns

In same ThreadPool thread● A parameter to the callback delegate

Hard to see point of this - but

Can be used for fire and forget

Explicit ThreadPool is better for this

Page 26: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

The system ThreadPool

A high level of control

When you manually create a thread

Priority, IsBackground, etc

You don’t need that level of control in every app

Creating a thread is cheaper than creating a process

But it’s not free – there are setup and teardown costs

The ThreadPool reuses threads

Page 27: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Thread reuse

When you explicitly create a Thread:

Thread executes the delegate passed to constructor

Thread dies when delegate returns

Thread is a foreground thread, by default

A TheadPool thread:

A background thread

Delegate to method of object with delegate fieldExecutes stored delegate

On return, add the thread to a ready list

A new stored delegate when wait handle signals

Page 28: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Cheaper and Less Code

Defers Thread destruction until process termination

More importantly:

Reusing threads reduces threads a process creates

ThreadPool takes less code, too

Just pass a delegate to a method, and it executes

Don't have to Start a Thread

Page 29: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Explicit ThreadPool

ThreadPool.QueueUserWorkItem static method

Executes a WaitCallback delegate

delegate void WaitCallback (object state)

Only one parameter, and it's untyped

Anonymous methods can capture state information(example on the next slide)

Page 30: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Explicit Example

private static void CaptureExample()

{

string Report = @"Some very big string";

string Filename = @"\A\Drive\Near\You\Report.txt";

ThreadPool.QueueUserWorkItem(delegate

{

WriteFile(Filename, Report);

} );

}

Captures Filename and Report from containing method.

Page 31: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Wait callbacks

The WaitCallback delegate is strangely named

It's often executed straight-away

The ThreadPool has a different sort of wait callback

ThreadPool.RegisterWaitForSingleObject

Takes a WaitOrTimerCallback delegate and a wait handle

More efficient, less reliable

One blocked thread, instead of many

May want to compile a blocking script

Page 32: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Thank you

Any Questions?

Page 33: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Midnight Beach

ContractingConsultingTraining

Page 34: Jon Shemitz Complicated stuff, quickly. Advanced Delegates.

Jon Shemitz

Talks fast.

Codes fast, too.