November 2005 - Posts

Take Ruby for a test-drive

If you haven’t been living in dark hole for the last six months, you’ve surely heard the buzz about dynamic languages, and Ruby in particular. Regular readers might recall me drawing some parallels between the new features in C# 3.0 and Ruby, but it doesn’t stop there. Things like anonymous methods and iterators have been around in Ruby for quite some time. If you’ve got ten minutes to spare, I highly recommend checking Ruby out. A good place to start is at Try Ruby! which is a browser based Interactive Ruby Prompt, or irb to those in the known. The site even sports a Ruby tutorial, just type “help” and follow the instructions. The Ruby syntax might be a bit unfamiliar at first, but you’ll get the hang of it in no-time. If you want to become a Ruby-expert, you can read the first edition of Dave Thomas’ excellent “Programming Ruby: The Pragmatic Programmers’ Guide” aka “The Pickaxe Book” online, or you can order the second edition from Amazon.

Here are some cool Ruby statements to try:

(3..6).each {|num| puts num}


(1..10).collect {|x| x*x}


def remember(&p)
    @block = p
end

remember {|name| puts "Hello, " + name + "!"}

@block.call("Your name here")


If you get the hang of things, and would like “the Java killer” to be a part of your tool chest. Just clickonce on the “Ruby One Click installer”.

Visual Studio 2005: Erronous MSDN documentation, Add Reference and the GAC

When I read this document on MSDN I got a little scared. The document claims that assemblies installed in the GAC will automatically be listed in the Add References dialog in Visual Studio 2005. Fortunately the documentation is wrong about this; assemblies in the GAC aren’t listed in Visual Studio. Why is this fortunate? To list an assembly in the Visual Studio IDE you’ll have to know what you’re doing. Developers like to learn things using a trial and error approach, and installing an assembly in the GAC might be something a developer would try since the assemblies listed in the Add Reference dialog are “shared”. I made this assumption way back in the Visual Studio .NET days. At the time I was ignorant about CAS, simply because I hadn’t had the time to learn about it, and didn’t know if there was a difference between GAC’ed and “regular” assemblies. If a GAC’ed assembly had appeared within the Visual Studio IDE, I’d probably keep installing assemblies into the GAC unnecessarily until I eventually learned more about the GAC and CAS. In .NET 2.0 assemblies installed in the GAC run with full thrust, this makes sense because you need administrative privileges to install an assembly in the GAC. Installing assemblies to the GAC just to have them appear in the Add References dialog could easily lead to gaping security holes in software.

So now that you know why adding an assembly to the GAC doesn’t add it to the Add References dialog, I’ll let you know how to add assemblies to that dialog. You’ve got several options.

  1. Add a new key under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx. If you want an installation only for the current user add the key to HKEY_CURRENT_USER instead. The value of the key should be the folder path that you want Visual Studio to look in for assemblies to include in the Add References dialog. This registry path is specific to VS 2005 and the .NET Framework 2.0 and will not work for previous versions of VS or the .NET Framework.
  2. Add a new key under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders. The value of the key should be the folder path that you want Visual Studio to look in for assemblies to include in the Add References dialog. This registry path is global and any folders listed here will be processed by VS .NET 2002, VS .NET 2003 and VS 2005 as well as the .NET Framework 1.0, 1.1 and 2.0. Keep backward compability in mind when choosing this option.
  3. Place a copy of your assembly in the Common7\IDE\PublicAssemblies folder beneath your Visual Studio 2005 installation folder (Typically c:\Program Files\Microsoft Visual Studio 8\). This is not a recommended approach; choose either option 1 or 2 if you can.

A dark day for patterns

John Vlissides, who was one of the authors of the legendary Gang of Four book, died from cancer this weekend. John's book is probably one of the most important books ever written on software architecture, and he has not only influenced many other technical writers, he has influenced the way we develop software today.
Rest in peace John, and many thanks for your contribution to the software architecture community.

How to: Deep copy any serializable object

Since most types in the .NET framework and in the class libraries you develop yourself are reference types, assigning one instance to another would have the two pointing to the same object. Because of this, the need to clone object is quite common within .NET applications. Out of the box, System.Object has a MemberwiseClone method which creates a shallow copy of the object. A shallow copy is a copy of the class members without copies of objects further down in the object graph. You can implement the IClonable interface, which defines a Clone method, to explicitly support deep cloning of your classes, but still client code has no guarantee that a class implementing the ICloneable interface creates a deep clone of an instance.
If you have a large class library, such as a domain model, implementing ICloneable will require much work and you’ll also have to ensure that your cloning algorithm functions as intended whenever you change your class. An option that I’ve seen many developers resort to is to use reflection to generalize the cloning algorithm. Reflection has some overhead, but it isn’t as slow as many people think. How ever, if you find the performance overhead of using reflection acceptable, there is a much easier and simpler way to deep clone an object.

As long as your types are serializable, you can use serialization to clone the object. Below is an example of a method that creates a deep clone of an object by serializing the instance to a MemoryStream, and then creates a cloned object by deserializing the stream to a new instance.
public static class XeroxMachine
{
   
public static T Clone<T>(T source)
    {
             
if (!typeof(T).IsSerializable)
              {
                    
throw new ArgumentException("The type must be serializable.","source");
              }
       
if (Object.ReferenceEquals(source, null))
        {
           
return default(T);
        }
        IFormatter formatter =
new BinaryFormatter();
        Stream stream =
new MemoryStream();
       
using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(
0, SeekOrigin.Begin);
           
return (T) formatter.Deserialize(stream);
        }
    }
}

Generics don’t have a way of restricting a generic type parameter to be serializable, therefore I’m checking asserting that the type is serializable before I clone it.
By using the XeroxMachine helper class, the ICloneable interface is a breeze to implement.

[Serializable]
public
class MyClass : ICloneable
{
      
public object Clone()
       {
             
return XeroxMachine.Clone(this);
       }
}

This technique works for every serializable type, and you’re guaranteed to get a true, deep copied clone of the object. Cloning an object this way is of course less efficient in terms of performance than writing your own type specific Clone method, but it is much more efficient when it comes to the time it takes to write the code.