Was this helpful?
This is in continuation to Reflection in .NET - Part 4
In our programs, we usually use early binding where the programmer declares the type of an object beforehand. In early binding, the type of the object used must be known at compile-time. Binding to a particular method is performed at compile-time before the program is run. When you build an assembly, you must give the references to external assemblies you use in your program. In case, if you don't have the references to external assemblies at compile time, the program will not compile. In other words, you will not be able to invoke methods of a type that the compiler is not able to resolve.
In late binding, the type of an object and the address of a method body is determined at runtime. The code to be executed is not determined until runtime. Late binding is also known as dynamic binding.
The methods declared as virtual or override in C# use late binding. However, it is a restricted kind of late binding. It only offers the flexibility of runtime binding to only those objects that belong to a particular inheritance chain i.e. the type of an object that you want to bind to must belong to a inheritance hierarchy.
Reflection offers complete late binding. At runtime, you can retrieve a list of types in a given assembly, then retrieve a list of methods of a particular type, create an instance of that type, and then invoke a particular method. In summary, you can make a call to a method belonging to an assembly that is not known at compile time.
It is important to note that late binding helps you gain flexibility at the cost of efficiency.
You can use the Activator.CreateInstance() method to dynamically create an instance whose type is not known until runtime. It invokes the constructor that matches the specified arguments. In case, you do not specify any arguments, then the default parameterless constructor is invoked.
Consider that your app needs the ability to support multiple printers such as HP Plotter, Epson Laser. And you do not want the app to adhere to a particular printer vendor product at compile time. The app should be able to identify which printers are available at runtime and the app user should be able to select any of the available printers. The app design should be flexible enough so that you should be able to include the new printers and exclude the existing ones whenever required.
If you bind early to a particular printer, then this application requires rebinding if it needs to use a different printer at a later point of time. This may require rewriting the app and recompiling it. We will use late binding to solve this problem. We will create the DLLs such as PrintToEpson.dll, PrintToHp.dll that will encapsulate the printing functionality. We will put these DLLs in the app directory. At runtime, we will load these DLLs, obtain the list all supported printers and ask the user to select a particular printer.
Using Activator.CreateInstance(), we will dynamically create an instance of the chosen Printer and invoke its Print() method. Note that the compiler doesn't know anything about all this at compile time.
Listing 1: Printer.cs
Printer is an abstract class that has an abstract method named Print(). Any printer-specific class will be derived from this abstract Printer class. Each such class will provide the concrete implementation of the Print() method.
We will make use of a custom attribute named NameAttribute that will be used to store the name of the printer. We will place this attribute on a printer-specific class. When the compiler discovers this attribute, it will emit the corresponding metadata. The attribute information stored in the metadata can then be queried at runtime via reflection.
Compile this file with the following command line: csc /t:library Printer.cs
Listing 2: PrintToEpson.cs
This file contains the classes that encapsulate the functionality of various Epson printers. For example, the PrintLaser class represents the Epson Action Laser 1000 printer. Since these classes will be derived from the Printer class, we need to refer to the Printer.dll during compilation using the /r option.
Compile this file with the following command line. csc /t:library PrintToEpson.cs /r:Printer.dll
Listing 3: PrintToHp.cs
Similarly this file contains the classes that encapsulate the functionality of various HP printers. Compile this file with the following command line: csc /t:library PrintToHp.cs /r:Printer.dll
Listing 4: LateBindingDemo.cs
Compile this file with the following command line. csc LateBindingDemo.cs /r:Printer.dll
|posted||Apr 20, 2016|
|active||Apr 20, 2016|
|•||Reflection in .NET - Part 4|
|•||Reflection in .NET - Part 3|
|•||Reflection in .NET - Part 2|
|•||Reflection in .NET - Part 1|
|•||.NET Core project option: "Produce outputs on build"|
|•||Fastest way to serialize a POCO to JSON and deserialize JSON to a POCO|
|•||Serialization in .NET - Part 4|
|•||Reading appsettings.json in a .NET Core console application|
|•||Serialization in .NET - Part 3|
|•||Serialization in .NET - Part 2|