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:
The 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 _source
and _target
</tt> 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.