In this article based on chapter 2 of Metaprogramming in .NET, authors explain how you
would use Reflection to get different objects to support the same functionality.
Metaprogramming in .NET can incorporate many different concepts and techniques. Some areas are easy to grasp, while others can be quite difficult. The best way to begin is to take a look at an API that’s been in .NET since version 1: Reflection. It provides a fairly simplistic introduction to core concepts of metaprogramming (such as introspection) and it gives you a glimpse into the structure of .NET code. Some of the practical uses of the Reflection API are:
Eliminating error-prone configurations
Creating an informative string representation of an object.
Enabling a simplistic duck-typing system.
If you’ve ever wanted different objects to support the same functionality (like implementing a Drive() method), you’d create either a base class or an interface that defined the method, and subclasses would implement it appropriately. Therefore, if you have an IDrive interface like this:
You could create a method that told any object to drive, so long as it implemented that interface:
However, there’s a less type-safe but more flexible version of this strategy. It’s called duck typing, and its key difference from the previous approach is that it doesn’t rely on inheritance hierarchies. Instead, all you need is a method that matches what you’re looking for. The existence of the method with the correct signature will make it It may surprise you that duck typing already exists in some form or another in .NET. One place is with operator
overloading. When you overload an operator, the compiler ends up creating a method with a well-known name. That’s what’s used when you use the operator.
NOTE: Duck typing is also used to allow developer to create enumerable objects without implementing IEnumerable<T> and IEnumerator<T>. For more details, please check out http://blogs.msdn.com/b/kcwalina/archive/2007/07/18/ducknotation.aspx.
For source code, sample chapters, the Online Author Forum, and other resources, go to
http://www.manning.com/hazzard/
For example, here’s a simplistic Range class that overloads the addition operator:
Produces “-10 : 15” on the command line, as expected. But what’s going on underneath the scenes? If you open up the assembly that contains this code in ILDasm and look at the definition of Range, you’ll find a method called “op_Addition”.
When you type “+” in your code, you’re telling the compiler to look for a static method with the name “op_Addition” and that’s marked with the specialname metadata flag. That’s what the operator keyword in C# does. You can’t just name a static method “op_Addition” and use it for addition because it won’t have that flag. The compiler sprinkles that in for you. But it has to use the name “op_Addition” because that’s the standard name for overloading “+” in .NET. Furthermore, it has to take two arguments. Therefore, if it quacks like a “+”, it Let’s see how we can implement duck typing with Reflection. For example, let’s say you had two classes that
both had Drive() methods but didn’t share a base class:
Duck typing says, “Well, they both look like they Drive(), and they act like they Drive(), so let’s make them Drive()”. You don’t care that there’s no common class between them; the method definition itself is what makes them common. With C# 4.0, the dynamic keyword gives you a somewhat limited version of duck typing out of the gate.
For source code, sample chapters, the Online Author Forum, and other resources, go to
http://www.manning.com/hazzard/
This gets the job done, but let’s take things one step farther by allowing the method name to be specified by the caller at runtime. Listing 1 shows an extension method that uses the capabilities of Reflection to invoke a desired Listing 1 Invoking a method via its name.
You look for the method based on the name and the types of the arguments given. In this case, the lookup is kept simple by only looking for public, instance methods. You get the argument types via Array.ConvertAll(), which tell Reflection which specific method to use in case the method is overloaded.
Real-world usage of run-time method invocation:
There’s one well-known .NET framework that uses this idea of resolving a method call at runtime, and it’s called CSLA (http://www.lhotka.net/cslanet/). It’s primarily used for business object development and it uses something called a DataPortal to manage object lifetime. The CSLA engine uses metaprogramming (to a degree) to determine which DataPortal_XYZ method to invoke based on the type of criteria given.
Now, you can call any method you want with relative ease:
Reflection is a concept that has been around a long time in many programming languages before .NET. Simply put,
Reflection is all about giving a developer the ability to read the contents of a program and execute its contents. The depth of reflection that languages and platforms offer varies, but generally any system that allows you to inspect and invoke code at runtime uses some form of reflection.
Authors:
Kevin Hazzard and Jason Bock
For source code, sample chapters, the Online Author Forum, and other resources, go to
http://www.manning.com/hazzard/
Compliments of manning.com is a 40% discount on all manning.com eBooks, pBooks and MEAPs (Manning Early Access Program). Please use promotional code high40code at manning.com. All pBooks include FREE PDF, epub and mobi formats.