08 Sep 2006 @ 4:59 PM 
 

How to use the Introspector (details)

 

RefGen is very useful. The UI generation is neat, but the best part is the Introspector. Take anywhere you’d use reflection to enumerate properties and access them dynamically and replace that Type.GetProperty().GetValue() with Introspector.GetProperty(srcObject, “propertyName”). Even better, use it to set properties. Even enumerating properties and their types is a breeze, and you only incur the cost of the reflection once.

First, lets get one thing straight: The function and usage of the Introspector’s methods will not change as I upgrade it, even though the backend will be optimized many times, so it’s safe to give you docs now.

Feature overview of the Introspector:

  • Automated ‘Learning’ of a Type’s properties
  • Dynamic access to properties by name (get, and set)
  • Fast object instantiation by Type name (beat the pants off of Activator.CreateInstance())
  • On-demand enumeration of the properties of a type, as well as access to the Type of each property
  • It’s Free and yes, you can put it in your commercial applications (in compliance with the Apache License v 2.0)

‘Type Learning’ is just a kitty cat way of saying that it enumerates the properties once using refleciton and caches what it finds. The major cost of using normal reflection based classes is incurred during the enumeration. Your average implementation of something using Reflection will run on average about 20 times slower than RefGen* because it will be enumerating or searching the properties with each access. When you make a call to the Introspector, and pass in an object of any type, the first thing it does is check the cache to see if it has been ‘learned.’ If it hasn’t, it learns it right then before proceeding with doing whatever you ask it to do. There is no need to give special instruction to the Introspector to learn the type. (Although you can force it with a blank call to Introspector.PropertyDictionary() without actually getting or setting anything.) The cache is static, so as long as the assembly doesn’t go out of scope, then it’s not going to have to re-learn the type again.

Getting Property Values:


public static object GetProperty(object Obj, string propertyName);
  

Ok, so how do we do it now? I figure I beat up on the Person object all the time, and it’s used to it, so lets use the Person object example from my previous post. Ok, so this is a cheesy, not a practical, example but we’ll talk about practical uses in a bit.


Person me = new Person();
Person.Name = "Dave Dolan";
      
// oh no! I forget what I just typed, so lets read the name again and print it to the console
 
string NameOfMe = (string) Introspector.GetProperty(me, "Name");
 
Console.Out.WriteLine("The value of the Name property for the Person \"me\" is {0}", NameOfMe);
 
  

Setting Property Values:


public static void SetProperty(object Obj, string propertyName, object value);
  

So now we want to set properties. This is just as easy as getting them.


Person me = new Person();
 
Introspector.SetProperty(me, "Name", "Dave Dolan");
      
// oh no! I forget what I just typed, so lets read the name again and print it to the console
 
string NameOfMe = me.Name;
 
Console.Out.WriteLine("The value of the Name property for the Person \"me\" is {0}", NameOfMe);
  

That’s mostly all there is to it with the property access. There is one thing left if you’re very nitpicky about casting too often.

You can save yourself one cast operation in the GetProperty method if you know upfront exactly which type you’re expecting by using the generic form of GetProperty.


public static T GetProperty<T>(object Obj, string propertyName);
  

Internally the output will still be converted to the type specified in the generic, but on the way out, at least you don’t have to cast it in your code. (This is why I say it only saves one cast op)


string NameOfMe = Introspector.GetProperty<string>(me, "Name");
  

Same deal applies with SetProperty, except it saves more like 1.5 casting operations becase when we pass the object typed parameter to the delegate that actually calls the setter, it’ll use implicit type conversion, which is a bit less expensive than a full out cast. (I made the .5 up so it’s 1.something, just for the record.)


Introspector.SetProperty<string>(me, "Name", "Dave Dolan");
  

Now value types (ints, floats, doubles, DateTimes and the like) will still be boxed because they’re passed to the delegate that invokes the setter as the type Object, which is something I hope to change in coming versions. (I’m going to multiplex the cache so that it stores a separate list of delegates for each target type, with strong types implemented directly in the IL.) So for now, figure that boxing still happens.

Property Enumeration:


public static Dictionary<string,Type> PropertyDictionary(object Obj);
 
// OR
 
public static Dictionary<string,Type> PropertyDictionary(Type t);
  

This provides you with a dictionary keyed by string property names, and housing their types. If you’d like the know what type
the “DateOfBirth” property of Person is then you can do this one of two ways, depending on what you know up front.


// using an instance of the object, if you don't know the type at design time
Type DoBType = Introspector.PropertyDictionary(me)["DateOfBirth"];
 
// OR
 
// using a the type of the object, if you happen to know it at design time
Type DoBType = Instrospector.PropertyDictionary(typeof(Person))["DateOfBirth"];
 
  

Up to now all of these methods caused the learning of a type. If you want to create an instance of the object, without being slow like the System.Reflection.Activator() then you can call Introspector.CreateObject(). The only catch is that the type has to have been learned, or you have to specify the assembly qualified name of it (which can be long)


public static object CreateObject(string ShortNameOfTheType);
  

This is particularly good for factories or custom-built data source controls in which you won’t know the type at design time, but
you’ll have already accessed the type using the Introspector before. ( If you haven’t, and you have an instance of it laying around you can call Introspector.PropertyDictionary(instanceOfTheType) and it will do nothing except learn the type) I’ll probably want to have a ’search for the type name’ feature added, but then I’d have to require you specify the full type name instead of just the short type name, or things might get hairy… It’s one of those features where I’d like to get input from people who’d actually use it before I make a decision.


Person meAgain = Introspector.CreateObject("Person") as Person; // note the 'as' clause because it's of type object
  

I hope that you’ll find this library useful, because I know I personally have come up with so many uses for it, like a simple way to generate ORMappers via factories, a way to create ‘linear’ serializers that have zero conditional logic or looping, and a way to ‘debug’ print out any type of object in the universe to the console without caring what kind of object it actually is, and oh, Generating a set of widgets to edit an object via a webpage with the ability to hook up datasources to them (Dolan.RefGen.UI.Web.ObjectWidget). I’m sure there are a million more but I’m just starting on this whole thing. I’d like to be able to do something nice for people without Full Trust too, so I have the idea that maybe I can pregenerate the assembly full of classes instead of delegates on the developers host and allow for it to dynamically load that at runtime. I mean, it’s probably not that often that you’d be using someone else’s classes that you have absolutely no knowledge of (unless you are also dynamically loading assemblies), so it’d work for your ORMapper and similar things still. (Not to mention that it would save on the time it takes to refactor your mappings when requirements change for your project.) Let me know what you think folks, and again the link is http://sourceforge.net/projects/refgen .

I’m so very open to suggestions it’s not even funny.

Lonely footnote from above:
*This is assuming that you are able to use the DynamicMethod in your environment (which requires Full Trust permissions)

Tags Categories: .NET Coding Posted By: Dave
Last Edit: 08 Sep 2006 @ 05 19 PM

E-mailPermalink
 

Responses to this post » (None)

 


Comments are open. Feel free to leave a comment below.


 Comment Meta:
RSS Feed for comments
TrackBack URI
 

Leave A Comment ...

 

 XHTML:
You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
\/ More Options ...
Change Theme...
  • Role »
  • Posts »
  • Comments »
Change Theme...
  • VoidVoid (Default)
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LiteLightweight
  • No Child Pages...