Internationalization: Creating a custom culture
Web 2.0 Bubble

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

Comments

Julio César

Nice article!: concrete, practical and useful. Just what I was looking for...

Thanks a lot.

Moim Hossain

Good post. Basically, I have seen that we know these stuffs about generics but for some reason (!) we don't use practice them.
This blog post certainly give me a reminder next time while I will write code and there is a scope applying these beauty of generics.
Thanks!

NinjaCross

Well developed post.
Even if I use Generics from their early introduction, i really enjoyed reading this post :)

shaiju

Cool man. gr8. Thanks

test

How do we constrain a generic to a nullable type

private static bool ProcessNullableValue(object target) where T : Nullable

Use

Rita

Hi,
Thanks for this article. I found it very useful. As a beginner to generics, I found it a bit advanced. But yes, I did go through other articles before I went through this.

http://www.kanbal.com/index.php?/Net-Frame-Work/generics-in-net-20.html[^][^]

The above can be used if you are a begineer like me. Once you read the above, this article would be cake walk. Ofcourse this article would give a completeness to the understanding of generics.

Tucker

I'm inclined to agree with you.
http://www.pdfqueen.com

rubyoxy

Although I think it's great work, my only criticism is at the syntactical (and somewhat superficial) level.

Impotence causes

Very good day to everyone. My name is James, I would firstly like to thank the creators of the blog for allowing me to express my opinion. Any friend or acquaintance I would recommend this article, is great, effective, comprehensive and dynamic. I was very young I have always admired people who are dedicated to reporting and writing on public issues, I think they are very special, just the fact that they are dedicated to publishing articles for everybody and that is admirable.

Cheap viagra

All have very nice day! a very special greeting to the artist who created this article was great, I think some criticism on blogs are what give it that spicy that makes them interesting, which is why I bring my little criticism. Many thanks.

Meeta

Hi Shafqat,

I am a Development Editor working with Packt. We are planning to publish a book on .Net Generics. I am looking for technical reviewers to provide feedback
on the content of the book. It would be of great help, if you would be willing to take it up. Please visit http://www.packtpub.com/author_reviewing_for_packt for more details regarding reviewing.We will also like you to know that you will be receiving two copies of the book- one eBook or print copy of the book you review and an eBook of your choice from our catalog once it is published and your name will be credited as well.

Thanks,
Meeta

ゼチーア

Hi there,
Really nice job,There are many people searching about that now they will find enough sources by your tips.
Also looking forward for more tips about that

The comments to this entry are closed.