Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Get Drunk on the Power of Reflection.Emit

With Reflection.Emit, you can add dynamic typing to your C# applications and enter a strange new world.


advertisement
# is a small language. It doesn't support writing regular expressions, for example, or accessing a relational database, or even using simple data-structures like stacks, queues, and lists. Of course C# programmers use these things every day through class libraries that ship with .NET. The point is that text processing, data objects, and collections are platform features, not language features.

There's nothing too surprising about using class libraries to supplement programming language facilities. What is surprising is that the .NET framework allows you to simulate the features of a dynamically typed language using C#.

This article will take you through the process of dynamically generating new types, methods, and even code at runtime with .NET. For a geek like me, this is an interesting exercise even if the code never makes it to production. But programmatically manipulating type information is more useful and more common than you might think. The .NET framework uses Reflection.Emit in diverse areas, from regular expressions to remoting. So who knows—maybe you'll find a use for it too.



First Things First
Occasionally, C#'s static typing can seem excessively rigid. Let's say I have two classes with identical interfaces:

[Serializable] public class Gun { public virtual void Shoot() { MessageBox.Show("Bang!"); } } [Serializable] public class Camera { public virtual void Shoot() { MessageBox.Show("Click!"); } }

Since the two types are so similar, it might be nice to treat them interchangeably—maybe iterate through a collection of guns and cameras, shooting each of them. But, you can't because they don't share a common base class or a common interface.

With access to the source code, adding an interface implementation is easy. But it turns out you can add an interface implementation dynamically as well using the Reflection.Emit namespace. The real advantage to this approach is that you only have to write the code once, and you can dynamically add an interface implementation to any class that exposes the necessary members.

Author's Note: What's with all the shooting?
I chose the names for these simple classes as a precautionary example. In general, .NET developers don't attach semantics to a method signature outside the context of a type. So identical methods on unrelated types that don't implement a common interface or share a common base class — like Gun.Shoot() and Camera.Shoot()— may not offer similar functionality at all. The point is: be careful.

Conceptually, building types dynamically is exactly the same as writing code by hand. With the Reflection.Emit namespace, you can do anything at runtime that you can do at compile time—but often in a way that's not so user friendly. Accordingly, my approach throughout this article will be to examine a static implementation first before showing you how to build the dynamic equivalent.

When building a standard, statically typed .NET application, the first thing you do is create a project. Similarly, before defining any dynamic classes, you need a place to put them. This part is pretty simple: Create a dynamic assembly, and then add a dynamic module. All of which should sound familiar because it's exactly the same thing that your IDE does for you when you're programming everyday. The only difference is that we're doing this at runtime.

Here's the code to dynamically build an assembly and a module:

AssemblyName an = new AssemblyName(); an.Name = "ExtendedTypes"; assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.RunAndSave); moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(OnAssemblyResolve);

Strategy #1: Subclassing On the Fly
Now it's time to start dynamically implementing interfaces. But first, let's review the plan. Both the Gun class and the Camera class need to implement a common interface called IShootable:

public interface IShootable { void Shoot(); }

If you were coding by hand, inheriting from a common interface would be very simple:

public class ShootableCamera: IShootable{}

You might have done something like the above when working with third-party components. The dynamic equivalent isn't too much harder:

public Type Subclass (ModuleBuilder builder, Type target, Type interfaceToImplement, string newTypeName) { TypeAttributes attributes = TypeAttributes.Public | TypeAttributes.Serializable; TypeBuilder tb = moduleBuilder.DefineType( "newTypeName ", attributes, target); tb.AddInterfaceImplementation(toImplement); Type subClass = tb.CreateType(); return subClass; }

Figure 1. Your Gun Is Now IShootable: Now that you've dynamically added the interface, you can use the Gun class, wherever you'd use IShootable.
That code should look pretty straightforward. Here's the English-language translation: "Define a new type (subclassing an existing type) and add an interface implementation." The only non-intuitive line is the one containing the CreateType()—this is the method that "bakes in" any members, interfaces, etc, of the previous steps, and gets your new type ready for use.

That's it. You've just build a subtype dynamically. Let's give it a test run:

Type shootableGunType = Subclass( builder, typeof(gun), typeof(IShootable), "ShootableGun"); object shootableGun = Activator.CreateInstance( shootableGunType, true); (shootableGun as IShootable).Shoot();

In the simplest case, all you have to do is create the subtype, create an instance of the subtype, and cast it to the appropriate interface (see Figure 1).



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap