The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








I heart FeedBurner

Latest Diggs - Programming

Computers Blogs - Blog Top Sites

Site Hits

Total: 4,870,568
since: 19 Jan 2005

Instantiating and Manipulating Classes at Runtime in C# and Objective-C

posted Thu 26 Jul 07

I was writing some code where I needed to create an instance of an object and then set some values for properties on that object. Seems like a pretty easy task, if you know the class type (and have a reference to it) at compile-time, but what do you do if all you have is a string representing the name of the class, and strings representing the names of various properties?

Of course, as a .NET programmer, I know that I can use Reflection. I have to ensure that I have a reference to the class that I intend to instantiate, but I can instantiate the class by name (provided I know the namespace as well) and I can manipulate properties by name as well. Take a look at the following code:

object o = Assembly.GetExecutingAssembly().CreateInstance("DynamicInstantation.Customer");
Type t = o.GetType();
PropertyInfo pi = t.GetProperty("FirstName");
pi.SetValue(o, "Kevin", null);
Console.WriteLine(string.Format(
   "New Property value is {0}", pi.GetValue(o, null)));

Yes, I am aware that I typo'd the namespace. So sue me. This works as intended and the output from running the program does indeed indicate that the FirstName property of my instance of the Customer class has been set to "Kevin". That's great, but what you might not have noticed here is that I have foreknowledge of the data type of the destination property. What the hell does that mean? It means that this works because I knew at compile-time that FirstName is a string. What happens if I get a string from my data source and try and set the Age (int) property to the string "42"? This is what happens:

Object of type 'System.String' cannot be converted to type 'System.Int32'

Pretty, isn't it? Of course we know that "42" can be Int32.Parse'd into an int..but, in order to know that we'd have to do runtime interrogation of the data types of either the destination or the source in order to use the Convert class to do on-the-fly data type conversion. In short, I'm opening a can of worms. LINQ might be able to help simplify things here by allowing me to write some type conversion language extensions to make the experience simpler, but it won't change the underlying nature of the beast.

So what does this look like in Objective-C? It might be a bit of an unfair comparison because Objective-C as a language is more dynamic than C#. However, I still think it's worth looking at given how C# and Objective-C are both peers in the sense that Objective-C is the driving language for Cocoa and C# is one of the driving languages for the .NET Framework. Here is some Objective-C code that creates an instance of a class based on it's string name at runtime and then sets the value of a property at runtime:

id theObject = [[NSClassFromString("Customer") alloc] init];
[theObject setValue:@"Kevin" forKey:@"FirstName"];
NSLog(@"The new property value is %@", [theObject valueForKey:@"Customer"]);

The first time I compiled this and it ran, I was shocked. I kept thinking, "Holy crap there's no way I should be able to do this... it's too...simple...". But it worked. Not only did it work, but if you are familiar with Key-Value-Coding, then you know that calling setValue:forKey: on a class actually invokes all notification triggers..meaning if you change values this way, bound GUI will be automatically notified, and this integrates well with the undo manager system. How cool is that?? To get that in C# we'd have to implement INotifyPropertyChanged on each model object and manually fire the changed event when the property changes. If you saw my WWDC presentation, then you'll know that one complain I have about "undo" support in C#/WPF is that you are not notified before a value changes, you are only notified after it changes. Which is utter crap, if you ask me.

So, given the code above...what happens if you try and send the value "42" to an integer-type column? It works. KVC is going to automatically attempt to coerce the source value into the type of the destination property. This means that you don't need to know at compile-time the data types of the properties, nor do you need to write code to interrogate the values. Obviously this has limitations, but for basic scalar primitives like floats and doubles and ints and strings, it seems to work like a charm.

Also keep in mind that while there's only a couple of lines difference in the code now, think of what it would look like if you had to deal with a lot of different properties. I can see the C# code getting ugly very fast without writing some helper code to keep things tidy.

The more I use Objective-C the more I become aware of it's elegance and power. I just really, really like that language.

tags:      

links: digg this    del.icio.us    technorati    reddit

AddThis Social Bookmark Button




1. Asd left...
Thu 26 Jul 07 11:09 am

Automatic type conversion is a great feature from other brilliant languages like Perl and VB /sarcasm


2. Kevin Hoffman left...
Thu 26 Jul 07 11:33 am

Don't confuse this with lack of strong typing. Objective-C is real C, with strong types. The "automatic" nature of this just means that under the hood Cocoa is doing the interrogation of the destination type and coercing the source value to that type for me.

I am going to pretend you didn't just compare Objective-C to VB. The concept boggles the mind.


3. cal left...
Thu 26 Jul 07 3:19 pm

Hi. I am assuming that your objc class "kevin" has an accessor method that deals with the variable "FirstName" (to support the KVC). What would happen if there was an ivar called "FirstName", but no accessors? Would this put your C# comparison on a more even footing?


4. Phil left...
Thu 26 Jul 07 3:30 pm

cal: All you need in that case is to hook up the class method + (BOOL)accessInstanceVariablesDirectly to return YES, and it continues to work. However, KVC is somewhat nicer than that, because if you have a -(void)setFirstName:(NSString *)name, you don't need an instance variable that corresponds with it (useful if you have values which are merely derived from other ivars, but don't need one themselves. As an example, you could have a "date" value & ivar, and a timeSinceDate value - you can still use setTimeSinceDate: without a reserved ivar for it! This example is somewhat contrived in its simplicity, but I believe it illustrates the point nicely)


5. cal left...
Thu 26 Jul 07 4:19 pm

phil: that's pretty cool. still trying to get my head around the whole kvc thing ... but as kevin states in the article - cocoa is full of pleasant surprises :)


6. David Orriss Jr left...
Thu 26 Jul 07 11:39 pm :: http://www.codethought.com/blog

Kevin, chide not Asd for it's obvious he knows not what he says. All of those years coding in ASP.net has no doubt addled his brain. ;)

BTW, great article. I really enjoy reading your stuff on Cocoa and ObjC. Inspires me to learn how to write apps for my Mac...


7. Kevin Hoffman left...
Fri 27 Jul 07 5:29 am

As Phil mentions... if you don't have an ivar defined, then let's say you try and set the value for key "FirstName", (which is actually cased wrong..it should be firstName), then if you have an accessor called setfirstName:(NSString *)theName then ObjC is going to call that instead of setting the accessor, which gives you all kinds of extremely powerful possibilities for "virtual" properties, two-way calculated fields, etc. Also keep in mind that any key that you have defined can be _bound to your GUI_. Extremely powerful stuff.


8. Diego Vega left...
Mon 30 Jul 07 2:41 am :: http://diegov.blogspot.com

Hello Kevin, you may be aware of this already, but in .NET, you can easily do this with System.ComponentModel.TypeDescriptor.GetConverter(targetType). ConvertFromString(text). I have used this a lot, and it has worked well for my scenarios. Another programer and I wrote an extension for MbUnit se we could completely specify unit tests in a data driven way. We used this for passing parameters to class constructors, properties, fields, method parameters and then to coerce expected values to the right type for asserts. It was all specified in strings and then everything was converted to the aproppriate types in runtime. I can say we even saw surprisingly good performance.


9. Tim Bedford left...
Tue 04 Dec 07 9:34 am

Yes Obj-C comes out on top again, and I'm noticing a pattern with your posts. The features of Cocoa that bring out the expression of wonder in you are all possible because Obj-C is dynamic. These things are impossible to do simply and elegantly without that flexibility. The best thing is that Obj-C supports static typing too, choose to use compile time type checking to improve your code quality but don't be shackled by it.

Oh and how can you mention setValue:forKey: without it's older and more talented sibling setValue:forKeyPath: ?

If you could see that the reflective C# code equivalent of the former could quickly get verbose, try writing some C# code to mimic what setValue:forKeyPath: does.


Tag Related Posts

Would you like to touch my mono?

Mon 23 Nov 09 2:59 P GMT-05

Smart, Deep Property Notifications in CLINQ v2.0

Tue 07 Oct 08 1:15 P GMT-05
tags:          

Microsoft's Lofty Direction

Sun 05 Oct 08 2:30 P GMT-05

Apple drops the iPhone NDA for Released Software

Wed 01 Oct 08 3:54 P GMT-05
tags:          

Cappuccino, Objective-J, and You

Wed 10 Sep 08 6:14 P GMT-05

So I'm in the LA Times ;)

Wed 27 Aug 08 2:51 P GMT-05
tags:                  

MobileMe vs. Live Mesh Throwdown - Round 1

Wed 16 Jul 08 10:33 A GMT-05

Building Model Classes in C# and Cocoa

Sun 15 Jun 08 3:13 P GMT-05
tags:            

One Framework to Rule them All

Mon 25 Feb 08 6:49 P GMT-05

Leopard Code Sample : Sprinkling in some Bonjour

Tue 27 Nov 07 2:32 P GMT-05
tags:        

Leopard Sample: A Bound NSCollectionView

Mon 29 Oct 07 1:41 A GMT-05

Leopard is out - let the code samples begin!

Fri 26 Oct 07 10:09 A GMT-05
tags:          

Microsoft Codename Acropolis - Unwrapped

Wed 20 Jun 07 3:22 P GMT-05
tags:              

The dreaded language bleed-over has begun

Tue 19 Jun 07 6:23 P GMT-05
tags:        

Exploring the Delegate Design Pattern

Mon 14 May 07 6:30 P GMT-05

Core Data - Almost too Easy?

Wed 18 Apr 07 2:23 P GMT-05

Exploring the MVC Pattern in WPF

Tue 10 Apr 07 12:51 P GMT-05
tags:                      

My Little Pony .NET Unleashed 2007

Fri 30 Mar 07 1:59 P GMT-05

An experience with the Leopard beta

Mon 26 Mar 07 7:45 P GMT-05
tags:                

Authorness

Thu 15 Mar 07 1:44 P GMT-05

WPF Bindings == WTF Bindings?

Mon 12 Mar 07 6:31 P GMT-05

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

Cocoa Programming vs. WPF : NIB vs XAML

Tue 20 Feb 07 2:09 P GMT-05

Cocoa Bindings vs. WPF Binding

Thu 15 Feb 07 5:41 P GMT-05
tags:                

Objective-C 2.0 - Programming for wimps?

Wed 31 Jan 07 6:18 P GMT-05
tags:              

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05

Lambda Lambda Lambda

Sun 21 May 06 1:01 A GMT-05

The Adventures of LINQ (Not Zelda)

Fri 19 May 06 11:21 P GMT-05
tags: