Functional Composition with delegate in Visual C#.NET

Encoding QR in Visual C#.NET Functional Composition with delegate

Functional Composition with delegate
QR-Code Printer In Visual C#.NET
Using Barcode drawer for .NET framework Control to generate, create QR Code image in VS .NET applications.
www.OnBarcode.com
QR Code 2d Barcode Decoder In C#.NET
Using Barcode reader for .NET framework Control to read, scan read, scan image in .NET framework applications.
www.OnBarcode.com
We just wrote some code that wraps up a method call inside an object. The call itself is wrapped up in another method with a well-known signature. You can think of a delegate as solving that same sort of problem: it is an object that lets us wrap up a method call on another object (or class).
Making Code 3 Of 9 In Visual C#
Using Barcode printer for .NET Control to generate, create Code 39 image in .NET framework applications.
www.OnBarcode.com
Drawing PDF417 In Visual C#.NET
Using Barcode creation for Visual Studio .NET Control to generate, create PDF417 image in .NET applications.
www.OnBarcode.com
But while our DocumentProcess classes have their methods hardcoded into virtual function overrides, a delegate allows us to reference a specific function (from a given class or object instance) at runtime, then use the delegate to execute that function. So, in the same way that a variable can be considered to contain a reference to an object, a delegate can be thought to contain a reference to a function (see Figure 5-2).
Encoding Data Matrix In Visual C#
Using Barcode drawer for .NET Control to generate, create Data Matrix ECC200 image in .NET applications.
www.OnBarcode.com
Paint 2D In Visual C#.NET
Using Barcode generator for Visual Studio .NET Control to generate, create Matrix Barcode image in .NET applications.
www.OnBarcode.com
Before we get into the specific C# syntax, I just want to show you that there isn t anything mystical about a delegate; in fact, there is a class in the .NET Framework called Delegate which encapsulates the behavior for us. As you might expect, it uses properties to store the reference to the function. There are two, in fact: Method (which indicates which member function to use) and Target (which tells us the object on which the method should be executed, if any). As you can see, the whole thing is not totally dissimilar in concept from our previous DocumentProcess base class, but we don t need to derive from Delegate to supply the function to call. That ability has moved into a property instead. That s all there is to a delegate, really.
Paint GS1-128 In Visual C#
Using Barcode printer for VS .NET Control to generate, create EAN 128 image in .NET applications.
www.OnBarcode.com
Print Interleaved 2 Of 5 In C#.NET
Using Barcode maker for Visual Studio .NET Control to generate, create USS ITF 2/5 image in Visual Studio .NET applications.
www.OnBarcode.com
However, it is such a powerful and useful tool that the C# language designers have provided us with special language syntax to declare new Delegate types, assign the appropriate function, and then call it in a much more compact and expressive fashion. It also allows the compiler to check that all the parameter and return types match up along the way, rather than producing errors at runtime if you get it wrong. It is so compact, expressive, and powerful that you can probably get through your entire C# programming career without ever worrying about the classes the C# compiler emits which derive from that Delegate class and implement it all.
Quick Response Code Decoder In None
Using Barcode recognizer for Software Control to read, scan read, scan image in Software applications.
www.OnBarcode.com
QR-Code Creator In None
Using Barcode maker for Excel Control to generate, create QR Code image in Microsoft Excel applications.
www.OnBarcode.com
So, why have we just spent a page or so discussing these implementation details, if we re never going to see them again While you don t usually need to use the Delegate class directly, it is easy to get confused by language-specific voodoo and lose track of what a delegate really is: it is just an object, which in turn calls whichever function we like, all specified through a couple of properties.
Decoding EAN-13 Supplement 5 In VB.NET
Using Barcode scanner for .NET Control to read, scan read, scan image in VS .NET applications.
www.OnBarcode.com
EAN13 Drawer In Objective-C
Using Barcode drawer for iPhone Control to generate, create GS1 - 13 image in iPhone applications.
www.OnBarcode.com
Let s start by defining a new delegate type to reference our document processing functions. As I mentioned earlier, rather than using that Delegate class, C# lets us define a delegate type using syntax which looks pretty much like a function declaration, prefixed with the keyword delegate:
Denso QR Bar Code Scanner In Visual C#.NET
Using Barcode scanner for .NET Control to read, scan read, scan image in VS .NET applications.
www.OnBarcode.com
Generating Quick Response Code In Visual Basic .NET
Using Barcode creator for .NET Control to generate, create QR Code ISO/IEC18004 image in .NET applications.
www.OnBarcode.com
delegate void DocumentProcess(Document doc);
Create UCC-128 In None
Using Barcode maker for Online Control to generate, create EAN / UCC - 13 image in Online applications.
www.OnBarcode.com
EAN 13 Printer In None
Using Barcode drawer for Font Control to generate, create GS1 - 13 image in Font applications.
www.OnBarcode.com
That defines a delegate type for a method which returns void, and takes a single Document parameter. The delegate s type name is DocumentProcess.
GS1-128 Printer In Java
Using Barcode drawer for Java Control to generate, create EAN 128 image in Java applications.
www.OnBarcode.com
Code 3/9 Reader In None
Using Barcode scanner for Software Control to read, scan read, scan image in Software applications.
www.OnBarcode.com
Delegates Under the Hood
UPCA Printer In None
Using Barcode encoder for Software Control to generate, create UPC-A image in Software applications.
www.OnBarcode.com
Matrix Generator In Visual Basic .NET
Using Barcode generation for .NET framework Control to generate, create 2D Barcode image in .NET applications.
www.OnBarcode.com
Anyone who has sensibly decided not to go any further into the implementation details can skip this sidebar. For those still reading... When you declare a delegate like this, under the covers C# emits a class called DocumentProcess, derived from MulticastDelegate (which is a subclass of Delegate). Among other things, that emitted class has a function called Invoke(int param) which matches the signature we declared on the delegate. So how is Invoke implemented Surprisingly, it doesn t have any method body at all! Instead, all of the members of the emitted class are marked as special by the compiler, and the runtime actually provides the implementations so that it can (more or less) optimally dispatch the delegated function.
Having added the delegate, we have two types called DocumentProcess, which is not going to work. Let s get rid of our old DocumentProcess abstract base class, and the three
classes we derived from it. Isn t it satisfying, getting rid of code There is less to test and you are statistically likely to have fewer bugs. So how are we going to adapt our DocumentProcessor to use our new definition for the DocumentProcess type Take a look at Example 5-9.
class DocumentProcessor { private readonly List<DocumentProcess> processes = new List<DocumentProcess>(); public List<DocumentProcess> Processes { get { return processes; } } public void Process(Document doc) { foreach(DocumentProcess process in Processes) { // Hmmm... this doesn't work anymore process.Process(doc); } }
}
We re still storing a set of DocumentProcess objects, but those objects are now delegates to member functions that conform to the signature specified by the DocumentProcess delegate. We can still iterate over the process collection, but we no longer have a Process method on the object. The equivalent function on the delegate type is a method called Invoke which matches the signature of our delegated function:
process.Invoke(doc);
While this works just fine, it is such a common thing to need to do with a delegate that C# lets us dispense with .Invoke entirely and treat the delegate as though it really was the function to which it delegates:
process(doc);
Here s the final version of our Process method:
public void Process(Document doc) { foreach(DocumentProcess process in Processes) { process(doc); } }
This can take a bit of getting used to, because our variable names are usually camelCased and our method names are usually PascalCased. Using function call syntax against a camelCased object can cause severe cognitive dissonance. I ve still never really gotten used to it myself, and I always feel like I need a sit-down and a cup of coffee when it happens.
Now we need to deal with the Configure method that sets up our processes. Rather than creating all those process classes, we need to create the delegate instances instead. You can construct a delegate instance just like any other object, using new, and passing the name of the function to which you wish to delegate as a constructor parameter:
static DocumentProcessor { DocumentProcessor rc rc.Processes.Add(new rc.Processes.Add(new rc.Processes.Add(new return rc; } Configure() = new DocumentProcessor(); DocumentProcess(DocumentProcesses.TranslateIntoFrench)); DocumentProcess(DocumentProcesses.Spellcheck)); DocumentProcess(DocumentProcesses.Repaginate));
However, C# has more syntactic shorthand that can do away with a lot of that boilerplate code. It can work out which delegate type you mean from context, and you only need to provide the method name itself:
static DocumentProcessor Configure() { DocumentProcessor rc = new DocumentProcessor(); rc.Processes.Add(DocumentProcesses.TranslateIntoFrench); rc.Processes.Add(DocumentProcesses.Spellcheck); rc.Processes.Add(DocumentProcesses.Repaginate); return rc; }
Not only have we achieved the same end in much less code, but we ve actually reduced coupling between our subsystems still further our DocumentProcessor doesn t depend on any classes other than the Document itself; it will work with any class, static or otherwise, that can provide a method that conforms to the appropriate signature, as defined by our delegate. So far, we ve only provided delegates to static functions, but this works just as well for an instance method on a class. Let s imagine we need to provide a trademark filter for our document, to ensure that we pick out any trademarks in an appropriate typeface. Example 5-10 shows our TrademarkFilter class.
class TrademarkFilter { readonly List<string> trademarks = new List<string>();
public List<string> Trademarks { get { return trademarks; } } public void HighlightTrademarks(Document doc) { // Split the document up into individual words string[] words = doc.Text.Split(' ', '.', ','); foreach( string word in words ) { if( Trademarks.Contains(word) ) { Console.WriteLine("Highlighting '{0}'", word); } } }
}
It maintains a list of Trademarks to pick out, and has a HighlightTrademarks method that does the actual work. Notice that it is coupled only to the Document it knows nothing about our processor infrastructure. Neither have we burned our base; we didn t have to inherit from any particular class to fit in with the processor framework, leaving it free for, say, our forthcoming highlighter framework. Example 5-11 shows how we add it to our configuration code.
static DocumentProcessor Configure() { DocumentProcessor rc = new DocumentProcessor(); rc.Processes.Add(DocumentProcesses.TranslateIntoFrench); rc.Processes.Add(DocumentProcesses.Spellcheck); rc.Processes.Add(DocumentProcesses.Repaginate); TrademarkFilter trademarkFilter = new TrademarkFilter(); trademarkFilter.Trademarks.Add("O'Reilly"); trademarkFilter.Trademarks.Add("millennium"); rc.Processes.Add(trademarkFilter.HighlightTrademarks); } return rc;
We create our TrademarkFilter object and add a few trademarks to its list. To specify a delegate to the method on that instance we use our reference to the instance and the name of the function on that instance. Notice that the syntax is very similar to a method call on an object, but without the parentheses.
If we compile and run, we get the expected output:
Processing document 1 Document traduit. Spellchecked document. Repaginated document. Processing document 2 Document traduit. Spellchecked document. Repaginated document. Highlighting 'millennium'
This pattern is very common in object-oriented design: an overall process encapsulated in a class is customized by allowing a client to specify some action or actions for it to execute somewhere within that process. Our DocumentProcess delegate is typical for this kind of action the function takes a single parameter of some type (the object our client wishes us to process), and returns void. Because we so often need delegates with this kind of signature, the framework provides us with a generic type that does away with the need to declare the delegate types explicitly, every time.
Copyright © OnBarcode.com . All rights reserved.