I left off last time talking about array transformation Commands, and mentioned they highlighted the troubles with inferring type information.
Remember that the parser can take a signature of
The reason all of the Convert methods do not take generics is for Java interoperability. Because the method can take any object, I need to lean heavily on the Reflection library to infer type information. (This is a situation where the new dynamic typing in C# 4.0 would have been invaluable!)
For example, let’s take the ElementSetter command. In IronRuby or C# 4.0, this would be a piece of cake. In Ruby, I could simply say something like:
Instead, I have to use type metadata to do the work:
ElementInfo class serves as an Adapter for the Reflection library’s PropertyInfo and FieldInfo classes, so that I can treat properties and fields the same throughout the rest of my code. The ID property of the
variables contain the name of the property. Under the covers, the ElementInfo
class just defers to the appropriate instance of either a PropertyInfo
or FieldInfo` class.
The logic behind finding the right
MethodInfo object to represent a conversion function is a little more challenging. I wrote a
MethodResolver class to handle the lookup of a method by its name. It can find both instance and static methods.
Another responsibility of the
MethodResolver class is handling generic types. Using the
Type.GetMethod() method, I can get a
MethodInfo object. MethodInfo contains a method
ContainsGenericParameters(). While that is true, there are open generic parameters to the method that need to be bound.
The last challenge to mention in this post is the creation of objects. How can one create a new instance of an arbitrary type. Generics provide some useful constructs like
default(T), but there is no convenient way to invoke this language feature outside of a generic method. And, as it turns out,
default(T) doesn’t always give me the answer I want.
I stumbled upon this in writing the array Command Decorator. I have an array of strings. I want to fill an array of integers by converting each member of the string array to an integer. But where do I get the new array from?
I tried a few casting solutions, but found that if I used an object, for example, the objects inside the array would appear to lose their type information and be just objects, which caused problems later in the process.
I also tried to write something like:
I have an issue, though. This generic method must now have the constraint new(), which means I have to handle arrays as a special case.
I found that by creating an
ObjectFactory class, it simplified other areas of the code. The
ObjectFactory, being a Factory, knows how to create new objects. It also holds a cache of previously created objects.
Activator lives in the
System namespace, and it’s what the .NET Framework uses for instantiating objects in
AppDomains. It works for my purposes, but as you can see, I did end up with some special handling of arrays in the end.
Having talked about some of the challenges of type inference, next post will discuss the conversion engine itself.