1 / 34

Jon Shemitz Complicated stuff, quickly.

Advanced Delegates. Jon Shemitz Complicated stuff, quickly. Advanced Delegates. Delegate syntax Delegate Arcana 40% Invocation lists, events, dynamic delegates Delegates vs interfaces Miscellaneous 2.0 enhancements Anonymous Methods 15% Delegates as t hread primitives

gianna
Télécharger la présentation

Jon Shemitz Complicated stuff, quickly.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Advanced Delegates Jon ShemitzComplicated stuff, quickly.

  2. 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%

  3. 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

  4. 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

  5. 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.

  6. 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

  7. (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

  8. 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

  9. 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. 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.

  10. 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.

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

  12. 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

  13. That's it for the basics Any questions? Advanced Delegates Anonymous Methods Asynchronous calls Delegates are asynch primitives

  14. 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.

  15. 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.)

  16. 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.

  17. Anonymous Method Syntax • delegate (optional parameters) {} 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) {};

  18. 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 programming EndInvoke is like Join, except it returns a typed result. Delegates are asynch primitives: Easiest way to pass parameters & get thread results.

  19. 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 thread Takes a string Returns a string May use ThreadPool directly if don't need result.

  20. 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

  21. EndInvoke • BeginInvoke starts asynch call • Collect results with .EndInvoke() Returns same type as delegate Whether void or string or whatever Can 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

  22. 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

  23. 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); } }

  24. 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

  25. 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

  26. 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

  27. 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 field Executes stored delegate On return, add the thread to a ready list A new stored delegate when wait handle signals

  28. 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

  29. 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)

  30. 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.

  31. 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

  32. Any Questions? Thank you

  33. Contracting Consulting Training Midnight Beach

  34. Talks fast. Codes fast, too. Jon Shemitz

More Related