Fun with Generics: Using constraints to limit Generics applicability using the 'where' keyword
December 22, 2007
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.
Nice article!: concrete, practical and useful. Just what I was looking for...
Thanks a lot.
Posted by: Julio César | December 31, 2007 at 03:30 AM
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!
Posted by: Moim Hossain | January 09, 2008 at 09:40 PM
Well developed post.
Even if I use Generics from their early introduction, i really enjoyed reading this post :)
Posted by: NinjaCross | January 21, 2008 at 05:25 PM
Cool man. gr8. Thanks
Posted by: shaiju | March 11, 2008 at 02:58 PM
How do we constrain a generic to a nullable type
private static bool ProcessNullableValue(object target) where T : Nullable
Use
Posted by: test | July 15, 2008 at 02:19 AM
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.
Posted by: Rita | November 28, 2008 at 12:08 AM
I'm inclined to agree with you.
http://www.pdfqueen.com
Posted by: Tucker | April 08, 2010 at 03:01 PM
Although I think it's great work, my only criticism is at the syntactical (and somewhat superficial) level.
Posted by: rubyoxy | September 02, 2010 at 04:39 PM
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.
Posted by: Impotence causes | October 09, 2010 at 02:09 AM
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.
Posted by: Cheap viagra | October 11, 2010 at 09:02 AM
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
Posted by: Meeta | November 17, 2010 at 11:12 AM
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
Posted by: ゼチーア | May 10, 2011 at 04:09 PM