Fun with Generics

Brian in Coding | 11 Comments November 20, 2003

Generics are a new feature in the .NET Framework that are at first glance similar to C++ templates. But, they run much deeper. Anyone who has been toying with the upcoming release of the .NET Framework may have seen generics in action in the new generic collection namespace:

List<int> intList = new List<int>();
list.Add(1);
list.Add(1);
int result = list[0] + list[1];

This creates a list of integers. Unlike a normal ArrayList, integers added to the list do not get boxed into objects. This can be done with C++ templating easily.

Here's a little deeper use of Generics that C++ can't touch. There is an interface called IServiceProvider that is essentially a hashtable of type->instance. We abuse this interface all over the place inside the Windows Forms designer, and typical usage looks something like this:

IServiceProvider provider = // get this from somewhere
IDesignerHost host; // interface you want an instance of
host = provider.GetService(typeof(IDesignerHost)) as IDesignerHost;

When you're through, you've got an instance to an object that implements IDesignerHost. Simple, right? True, but that last line is anything but pretty. There is a typeof and essentially a cast. I prefer the "as" syntax because it looks a little cleaner, but it is still a cast. This looks even worse in Visual Basic:

host = CType(provider.GetService(GetType(IDesignerHost)), IDesignerHost)

Yuck!

But Generics can make this better. In fact, almost Smoov. Here's a little generic method that wraps a member variable called _provider:

private T GetService<T>() {
    return (T)_provider.GetService(typeof(T));
}

Simple enough. Here's how you would use this:

host = GetService<IDesignerHost>();

It's a little ugly because I still need the open/close parens, but all of the typeof and casting junk is gone. Cool!

Comments (11) -

Frank Hileman, Saturday, November 22, 2003 at 11:40 AM

That is nice. I would often wrap the getservice in a property to make it cleaner. Your techniuqe is more general. What are you working on these days, the next winforms desginer?

Brian Pepin, Saturday, November 22, 2003 at 5:00 PM

Yes, mostly the next form designer. I've also worked on making it so you can easily host designers outside of Visual Studio. I think we can host the Winforms designer in about four lines of code, now, down from about 7000. Now that the PDC has "outed" us I'm planning to post more comments about Whidbey.

Frank Hileman, Monday, November 24, 2003 at 7:55 AM

That is GREAT!! I should add some more exclamation points!!!!!! Unfortunately, I think our designer has too much cruft and workarounds that are visual studio dependent right now. But this has always  been our goal, to reuse the code in and out. What about designer transactions? Is there something we can use for that?
By the way, you may want to look at our root desginer, for a product called VG.net. It is an animated graphics system similar to Avalon, but based on System.Drawing, completely integrated in Visual Studio. Having worked on similar systems, your ShapeDesigner was partially an inspiration, and partially a proof of concept for us. Without the infrastructure created by you and Shawn Burke, the integrated designer would not have happened. You should be proud.
We don't have the web page up yet but here are some screenshots:
http://www.prodigesoftware.com/screen1.png
http://www.prodigesoftware.com/screen2.png
http://www.prodigesoftware.com/screen5.png
www.prodigesoftware.com/animation_design.png
www.prodigesoftware.com/animation_sample.png
What do you think?

Brian Pepin, Tuesday, November 25, 2003 at 10:15 AM

Wow, those look fantastic!  (My turn with the exclamation points).  Designer Transactions hinge on a new service in Whidbey called the ComponentSerializationService.  (Pre-Whidbey we used IDesignerSerializationService but it is really ill-suited to transactions).  For Whidbey, nearly all services have some sort of turnkey implementation.  There is an implementation called CodeDomComponentSerializationService that uses the CodeDom serialization mechanism to implement the service.  Plug that in and you're halfway there to full transactions.  
The other half is UndoService, which is about 99% turnkey.  It requires a component serialization serivce and it requires you to implement an undo stack.  Implementing an undo stack really amounts to deriving from UndoService and adding an instance of a Stack class -- we make you do this part because typically you'll want to bolt that stack onto some UI to control undo and it was a reasonable extensibility point.  

Frank Hileman, Wednesday, November 26, 2003 at 6:10 AM

Thanks for the nice comments. This transaction support sounds great! Does not sound very hard to build a designer host now. But, I am a little confused as to which product this will belong to. VS.net (Whidbey)? So it will be possible to ship a designer host built this way, only to people who own VS.net? That is fine, just wondering about how we will build a designer for non-developers. I guess for that we still have to write a lot of code? Or is some of this in the .net framework itself?
I come from a real-time data (mainly process control) visualization background. We have a second root designer for real-time data binding, a function block-style editor, which does not use reflection at run-time (unlike avalon). I don't know when or if the data-binding designer will be finished, but when it is, we would have a complete visualization system for non-programmers (output would be dlls). So a standalone host might be advantageous at some point in the future.

Brian Pepin, Tuesday, December 2, 2003 at 11:34 PM

Nope, Whidbey is really two products:  VS .NET and the .NET Framework.  All this stuff is core to the framework itself.  VS uses it (and abuses it), but you can do all of this with just a free framework download.  No development environment needed!

Frank Hileman, Wednesday, December 3, 2003 at 5:55 AM

Ah, I didn't realize that. Wow, now I am really excited! This is an amazing designer framework for free. Very powerful, that transaction and serialization stuff (asuming codedom serialization/deserialization is there, since the transactions use it). I am going to have to find more docs on whidbey so I don't post a million questions here on your blog Smile

Thomas , Tuesday, September 6, 2005 at 3:50 PM

I found this post via google and hope that you get mail notifications.
I am currently working on a standalone form designer (-> Designer Hosting outside of Visual Studio). I am using  .net 2.0 beta features (like designsurface).
Things got a lot simpler with the usable implemenation of a SerializationService ( I am using CodeDomComponentSerializationService)
, and i already got copy/paste working.
But currently I have some problems with the UndoEngine.
I implemented a simple stack and a AddUndoUnit() method that pushes the last unit onto the stack. But how do I undo the last Unit?
I tried to pop of the stack and invoke Undo() of UndoUnit but this doesnt seem to work.

Brian Pepin, Thursday, September 8, 2005 at 8:58 AM

Thomas -- That is mostly all you have to do.  You should maintain two stacks of undo items:  one for undo, and one for redo.  As you undo items, place them on the redo stack.  I've added an upload to this post that contains some sample code that we were using to test this.  Give it a whirl and let me know what you find.

Thomas, Thursday, September 8, 2005 at 11:19 AM

Hi Brian!
Thanks for your reply.
There seems to be something wrong with the link. I am getting a 403.
Comments are closed