Previous month:
November 2007
Next month:
January 2008

December 2007

Fun with Generics: Using constraints to limit Generics applicability using the 'where' keyword

Generics was introduced in .NET with version 2.0. One feature that is very useful but rarely used is the constraints for Generics. Constraints allows the developer to limit the type that is used instead of any object. Let us try to understand this with a sample. Lets assume that we have a in memory cache class for a certain type of object which we will simulate in the sample using a dictionary. Lets look at the code sample

class MyCache<K, T>
{
    Dictionary<K, T> _store = new Dictionary<K ,T>();
    void CacheItem(K key, T obj)
    {
        _store[key] = obj;
    }

    T GetFromCache (K key)
    {
        if (_store.ContainsKey(key))
            return _store[key];
        else
            return default(T);
    }
}

Generics constraint for Reference Type

The above class looks pretty simple and easy to use. Now lets assume that we want to cache classes that are reference types and this MyCache class should not be use with any struct or value types. How can we do that? Here is how ...

class MyCache<K, T> where T: class

This 'where' keyword is telling the compiler that MyCache type can by applied on the reference types only.

Generics constraint for Value Type

Similarly we would use the following syntax for structs

class MyCache<K, T> where T: struct

Generics constraint for a specific interface

What if we have a specific requirement for the type to be disposable? For example when cache is disposed we want all the items that are in  the cache to be disposed as well. If we had no constraints in MyCahe class then we would have to write

public void Dispose()
{
    foreach (K key in _store.Keys)
    {
        IDisposable d = _store[key] as IDisposable;
        if (d != null) d.Dispose();
    }
}

Observe that we are casting to disposable type and then disposing the object. What if someone had used a type that does not implement IDisposable? Lets try to impose a constraint that says the the type T must be disposable.

class MyCache<K, T> : IDisposable where T:IDisposable

... and our dispose code should look like this ...

public void Dispose()
{
    foreach (K key in _store.Keys)
    {
        _store[key].Dispose();
    }
}

Please observe that since we have specified that the type T is a IDisposable type we can directly call the Dispose method.

Generics constraint on multiple types

Now suppose that I have a class named EntityBase that we are using for all our entity classes and the functionality of the MyCache to apply to the entity classes only. How do we tell generics to restrict MyCache to classes that derive from EntityBase and implements IDisposable? This is how ...

class MyCache<K, T> : IDisposable 
      where T:EntityBase, IDisposable

In the above code we are saying the that the type T must be subclass of EntityBase class and must be disposable. Please note that we would also be able to call methods and properties of the EntotyBase class directly without explicit casting as we have already shown in the disposable example.

Generics constraint on multiple items

What if we wanted the the key to always a value type? Let try to add that to our definition.

class MyCache<K, T> : IDisposable 
      where K:struct
      where T:EntityBase, IDisposable

Specifying a default constructor

Sometimes we might want to write code like new T() to instantiate a variable of type T. This will not work if the class do not have a default constructor. In order to make sure that T has such a default constructor we would write ...

class MyCache<K, T> : IDisposable 
     where K:struct
     where T:EntityBase, IDisposable, new()

The new() keyword will make sure that the T has such a default constructor, otherwise it will not compile.

An interesting tip : Aliasing

We can also use aliases to use generic types in our classes. Sometimes too much generic expression makes the code look bad with lots of <> and <>. This can be avoided via aliasing. You can give a alias or name to a certain generic type and use it from the class. See example below

using StringQueue = System.Collections.Generic.Queue<string>;

Here we are making a generic Queue class bound with string to be named as StringQueue which later used in code like this ...

StringQueue queue = new StringQueue();
queue.Enqueue("Sometext");

Fun, isn't it?

The Last Word

Unfortunately the above feature of generics is usually overlooked and rarely used in code. Better OO design can result from using these features. Lets try to use this when we design object model in our daily life.

kick it on DotNetKicks.com


Internationalization: Creating a custom culture

.NET Runtime ships with several languages and support for creating a custom language. But the Operating System or the .NET did not have built in support for my native language "Bangla". In order to implement Bangla in my program I had to create a custom culture and write the resource files for that custom language. Once a language has been created and registered it does not need to be created again. So in a windows PC the registration code should run only once. See the code below which shows how to achieve this by using CultureAndRegionInfoBuilder class.

CultureAndRegionInfoBuilder builder =new CultureAndRegionInfoBuilder("bn",
              CultureAndRegionModifiers.Neutral);

// there is no neutral Bengali culture to set the parent
builder.Parent = CultureInfo.InvariantCulture;
builder.CultureEnglishName = "Bengali (Bangladesh)";
builder.CultureNativeName = "বাংলা";
builder.ThreeLetterISOLanguageName = "ben";
builder.ThreeLetterWindowsLanguageName = "ben";
builder.TwoLetterISOLanguageName = "bn";
builder.IetfLanguageTag = "bn-BD";
builder.KeyboardLayoutId = 1081;
builder.TextInfo = CultureInfo.InvariantCulture.TextInfo;
builder.CompareInfo = CultureInfo.InvariantCulture.CompareInfo;

// Register the culture
builder.Register();

How do use this custom culture in our code? Here is how ...

Thread.CurrentThread.CurrentCulture = 
         CultureInfo.CreateSpecificCulture("bn");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("bn");
This should be done before loading the UI. I am assuming that the reader know all about custom resource files and how to use them

kick it on DotNetKicks.com


In love with Enso: C# Plugin framework for Enso with sample text replace plugin

I have fallen in love with Enso, which is an application launcher and much more from Humanized, Inc. It has potential to do so much more than application launch ... it is a awesome productivity enhancer. It takes me a 3 seconds to do stuff that took half a minute. It is better than Launchy and the other products on the market. It is like Quicksilver for windows. I have decided to write my own plugins for Enso and within a few hours did so.

In order to write this extension I needed to find the extension API which was located here. Also you need to download the Enso Developer prototype ( still at version 0.1.1). Unfortunately there was no SOAP support at the moement, all I found was the Xml-Rpc procedures. So I looked for a Xml Rpc library written in .NET and found Cook computings open source implementation at http://www.xml-rpc.net/.

The first step was to create a class that could access all of Enso's exposed functions. The following class below is the proxy class for the Xml-Rpc support in Enso.

public interface IEnso: IXmlRpcProxy
{
    [XmlRpcMethod("displayMessage")]
    bool DisplayMessage (string text);

    [XmlRpcMethod("getFileSelection")]
    string[] GetFileSelection();

    [XmlRpcMethod("getUnicodeSelection")]
    string GetUnicodeSelection();

    [XmlRpcMethod("insertUnicodeAtCursor")]
    void InsertUnicodeAtCursor(string text, string fromCommand);

    [XmlRpcMethod("registerCommand")]
    bool RegisterCommand(string url, string name, string description, string help, string postfixType);

    [XmlRpcMethod("setCommandValidPostfixes")]
    bool SetCommandValidPostfixes(string url, string name, string postfixes);

    [XmlRpcMethod("setUnicodeSelection")]
    bool SetUnicodeSelection(string text, string fromCommand);

    [XmlRpcMethod("unregisterCommand")]
    bool UnregisterCommand(string url, string name);
}

Then I wrapped a nice class called 'EnsoControl' around the proxy. Now to make an extension ...

Now our extension must implement a method that is invoked by Enso when the command is typed by the user. The interface looks like the one below ..

 public interface IEnsoExtension
 {     [XmlRpcMethod("callCommand")]     void callCommand(string name, string postfix);
 }

The extension needs to implement this method in our class.

Try seeing the sample class inside the extension framework zip file which provides a simple replacement command in Enso. Also I had to add an http handler ( details are in the Xml Rpc site) to server the XmlRpc calls.

You can download the source code for Download EnsoExtension.zip .

See the Enso sample replacement extension in action

kick it on DotNetKicks.com

Threading posts temporarily discontinued

I have started a five part series of posts on threading in .NET and the first part was published. But it seems that there is a free web e-book available on threading. So I have decided to postpone the posts on threading. Instead I will be posting on new stuff on .NET and whatever interesting stuff I stumble on.

Independent Thought

Now, online companies offer 000-890 question packages that hold similar questions that are asked in IBM certification. Other than IBM, Citrix certification 1Y0-327 is also provided which hold 66 questions that can be answered in 90 minutes. Solaris 310-302 on the other hand is different from above given certificates and that is due to the difference in questions. Novel 50-686 certification is similar to the certification of IBM holding computer based questions. The 642-533 is the IPS Implementing Cisco Intrusion Prevention Systems exam which is associated with the Cisco Certified Security Professional certification. Whereas, 70-229 is the MCSD.NET SQL Server 2000 Design exam which includes 409 questions, and 178 study notes. Adobe technology introduces 9A0-045 training.