Search
Close this search box.

C#/.NET Five Final Little Wonders That Make Code Better (3 of 3)

This week is my final entry in my Little Wonders series (posts one and two are here and here).  These are those little tips and tricks in .NET (and in particular C#) that may not seem like much, but can help make your code either more concise, maintainable, or performant.

Thanks again for all your comments and suggestions on this series, it has been a lot of fun to write, and though I feel I could go on forever with lots more tips and tricks, this will be the last Little Wonders post for a while.

1. Implicit Typing

First of all, let’s set the record straight for those confused: implicit typing is not dynamic typing.  Any identifier that is implicitly typed with the keyword var is still strongly typed.  The only difference is that the type is implied from the assignment expression.

Many think implicit typing is somehow lazy or inferior.  I must admit that when I first saw it I kind of felt the same way, but then after thinking about life in C++ with the STL iterators when you typed stuff like:

   1: for (list<int>::const_iterator it = myList.begin(); it != myList.end(); ++it)
   2: {
   3:     // ...
   4: }

I began to realize how much of a time-saver, and readability-saver, implicit typing is (those of you in C++ will be happy to know you now have implicit typing through the rebirth of the auto keyword).

For example, how many times do you have to type code like this:

1: // pretty obvious
2: ActiveOrdersDataAccessObject obj = new ActiveOrdersDataAccessObject();
3:  
4: // still obvious but even more typing
5: Dictionary<string,List<Product>> productsByCategory = new Dictionary<string,List<Product>>();

Does explicitly typing obj or productsByCategory here really gain you anything?  Isn’t it obvious what the types are since we’re assigning them in the same statement?  It is so much cleaner just to say:

   1: // nicer!
   2: var obj = new ActiveOrdersDataAccessObject();
   3:  
   4: // Ah, so much nicer!
   5: var productsByCategory = new Dictionary<string,List<Product>>();

And let the var keyword do the work for you.  C# will examine the assignment expression and see what type it is, and then do the assignment.

Now obviously, there are times you want your variable to be a super-class or interface and those times explicit typing is what you’ll need, but don’t shy away from var because some think it’s lazy.  It can be abused, like any good tool, but it can also really improve your readability.

In fact, it really improves readability with generics and with LINQ expressions.  For example, compare these two:

1: // implicit typing
2: var results1 = from p in products where p.Value > 100 group p by p.Category;
3:  
4: // explicit typing
5: IEnumerable<IGrouping<string, Product>> results2 = from p in products where p.Value > 100 group p by p.Category;

Whenever you start making heavy use of generics, collections, and especially LINQ expressions, you can rely on var to both make your code more readable, and to figure out what the type of the expression will be for you. 

2. LINQ Extension Methods

How many times have you written your own sort, find, grouping, or any other such standard algorithm?  Now how many hours have you spent writing unit tests for those methods?  And finally how many times have you been bitten by a trivial bug in one of those simple algorithms because of a typo?

With the LINQ extension methods, you have an arsenal of ready-made algorithms at your finger-tips which have already been tuned and unit-tested.  Really and truly, you should never have to write those standard algorithms again. 

Want to sort?  Use OrderBy().  Want to filter by a condition?  Use Where().  Want to select a subset of properties?  Use Select().  Want to group by a property?  Use GroupBy().  These are just a small taste of the many extension methods that were added to support LINQ and they are are fully tested and tuned!

For example, let’s say you have a List<Product> where Product, among other things, has a Value and a Category.  And let’s say you want to find a list of your high value products (> $100) by category.  Well, if you want to do it old-school you could write:

   1: var results = new Dictionary<string, List<Product>>();
   2:  
   3: foreach (var p in products)
   4: {
   5:     if (p.Value > 100)
   6:     {
   7:         List<Product> productsByGroup;
   8:         if (!results.TryGetValue(p.Category, out productsByGroup))
   9:         {
  10:             productsByGroup = new List<Product>();
  11:             results.Add(p.Category, productsByGroup);
  12:         }
  13:  
  14:         productsByGroup.Add(p);
  15:     }
  16: }

but that’s quite a mouthful of code, and to make matters worse if we do anything wrong it could be erroneous as well.  Why not just use the LINQ extension methods instead:

   1: var results = products
   2:     .Where(p => p.Value > 100)
   3:     .GroupBy(p => p.Category);

Or if you like, as a LINQ to objects expression:

   1: var results = from p in products where p.Value > 100 group p by p.Category;

The algorithms are already written for you and unit tested to boot!  Why rewrite code and risk the bugs?  Yes, you’ll have to learn lambda expressions or the LINQ query language if you aren’t used to them yet, but once you do a whole new world of powerful algorithms and expressions will be open to you!

3. Extension Methods

Depending on who you talk to extension methods are either the embodiment of evil, or really cool.  I tend to find them somewhere in between.  Are they as cool or as powerful as LINQ?  No, but it’s largely due to them that LINQ has a lot of its power. 

So why did Microsoft give us extension methods?  Why not just expand all the collections with various Select(), Where(), and other such LINQ methods?  Well, the answer is that not all collections have the same base classes and very few of them are implemented the same way.  In fact the one interface that seems to tie the most collections together is IEnumerableand as you know, you can’t add functionality to an interface directly.

So Microsoft added the ability to create a static method in a static class that behaves like it’s a member of the class that it is called on.  This has some interesting ramifications including that you can call an extension method off of a null reference (whether or not you should do this is hotly debated of course).

So let’s say you want to create an extension method that makes it easy to turn any object into anXML string.  We could write:

   1: public static class ObjectExtensions
   2: {
   3:     public static string ToXml(this object input, bool shouldPrettyPrint)
   4:     {
   5:         if (input == null) throw new ArgumentNullException("input");
   6:  
   7:         var xs = new XmlSerializer(input.GetType());
   8:         
   9:         using (var memoryStream = new MemoryStream())
 10:         using (var xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding()))
  11:         {
  12:             xs.Serialize(xmlTextWriter, input);
  13:             return Encoding.UTF8.GetString(memoryStream.ToArray());
  14:         }
  15:     }
  16: }

Note that the class we define the extension methods in must be a static class, and the first parameter of the extension method has the keyword this in front of its type.  This means that this static method will be invoke-able directly from any object of that type (in this case object, or anything).

Now, we can easily write

1: // can convert primatives to xml
2: string intXml = 5.ToXml();
3:  
4: // can convert complex types to xml
5: string objXml = employee.ToXml();
6:  
7: // can even call as static method if you choose:
8: objXml = ObjectExtensions.ToXml(employee);

Note that this is just syntactical candy.  You are not really providing anything special here other than the fact that you can treat the extension method as if it is a member of the type it is “extending”.  As such, it is a very powerful tool in your toolbox for making code more readable, but be careful!  Overusing extension methods can make code less readable and may pollute your IntelliSense.

As general rules of thumb, I say prefer extension methods for types that you cannot extend (not yours or sealed) or for adding global functionality for interfaces (like IEnumerable).  But if the class is already under your control, prefer to add a real instance method instead.

4. System.IO.Path

The .NET System.IO.Path class has a plethora of static methods for dealing with files and paths that should make any manual manipulation on your side obsolete.

How many times have you tried to combine a path name and file name by hand and ended up botching it up because you expected (or didn’t expect) the path to have a trailing path separator (‘\’) character?  Well, there is the Path.Combine() static method that can take care of that:

   1: // combines a series of path name components into one path
   2: string fullPath = Path.Combine(workingDirectory, fileName);

Or what if you have a fully qualified path name to a file and you just want the file name, or just the path itself, or just the extension?  There are a plethora of Path static methods for giving you what you need!  No more need to do string searches and substrings when you can just use these:

   1: string fullPath = "c:\\Downloads\\output\\t0.html";
   2:  
   3: // gets "c:\"
   4: string pathPart = Path.GetPathRoot(fullPath);
   5:  
   6: // gets "t0.html"
   7: string filePart = Path.GetFileName(fullPath);
   8:  
   9: // gets ".html"
  10: string extPart = Path.GetExtension(fullPath);
  11:  
  12: // gets "c:\downloads\output"
  13: string dirPart = Path.GetDirectoryName(fullPath);

So before you go manually manipulating those filenames and paths, consider the Path class and its static methods.

5. Generic Delegates

If you’ve ever written or used a class that had events, or used one of the many of the LINQ extension methods, then chances are you’ve used either directly or indirectly used delegates.  Delegates are a powerful way to be able to create type that can be used to describe a method’s signature.  The actual method used and invoked, then, is specified later at runtime.  In C++ terms this is akin to using pointers-to-functions.

The great thing about delegates is they can make classes so much more reusable than inheritance can.  For example, let’s say you want to design a cache class and that class will contain a method, provided by the class’s user, that will determine if a cache item has expired and can be removed.  You could provide an abstract method that the user has to provide, but this means that the user would have to extend your class and override the method, which means a lot of extra work for providing that functionality.  In addition, this means you can’t mark your class as sealed to protect it from other non-related changes during inheritance.

This is where delegates become really powerful, you could provide a delegate that would specify a method type that can be called to check a cache item to see if it’s expired, and then when the user instantiates your cache, they can pass in or set the delegate to the method, anonymous delegate, or lambda they want called.  This way, no subclass is necessary and in fact you can seal your class to prevent unintentional changes.  This makes the class much more safe and reusable.

So what does this have to do with generic delegates?  Well, there are three basic “types” of delegates that appear over and over again, and rather than having to write these delegate types repeatedly, .NET has done you a big favor by making them generic so that they can be used repeatedly.  This also has the added benefit of making code that depends on delegates more readable, as these generic delegates are well understood in usage and intention:

  • Action<T> – A method that takes an argument of type T and returns void – generally used to perform an action on an item.
  • Predicate<T> – A method that takes an argument of type and returns a bool – generally used to determine if an item meets a condition.
  • Func<TResult> – A method that returns a result of type TResult – generally used to generate values.

Note that these are the base forms of these generic delegates, and there are versions that take multiple parameters for each, the main thing that is constant is that Action returns void, Predicate returns bool, and Func returns a specified result.

So, to our cache example, say you wanted to write that cache that accepts a caching strategy, you would want a delegate that operates on an argument and returns a bool as to whether it has expired, that sounds like a Predicate:

   1: public sealed class CacheItem<T>
   2: {
   3:     public DateTime Created { get; set; }
   4:  
   5:     public DateTime LastAccess { get; set; }
   6:  
   7:     public T Value { get; set; }
   8: }
   9:  
  10: public sealed class Cache<T>
  11: {
  12:     private ConcurrentDictionary<string, CacheItem<T>> _cache;
  13:     private Predicate<CacheItem<T>> _expirationStrategy;
  14:  
  15:     public Cache(Predicate<CacheItem<T>> expirationStrategy)
  16:     {
  17:         // set the delegate
  18:         _expirationStrategy = expirationStrategy;
  19:     }
  20:  
  21:     // ...
  22:  
  23:     private void CheckForExpired()
  24:     {
  25:         foreach (var item in _cache)
  26:         {
  27:             // call the delegate
  28:             if (_expirationStrategy(item.Value))
  29:             {
  30:                 // remove the item...
  31:             }
  32:         }
  33:     }
  34: }

Then you can create the cache and use it without needing to sub-class. 

   1: var cache = new Cache<int>(item => DateTime.Now - item.LastAccess > TimeSpan.FromSeconds(30));

In fact, we can create as many caches we want with as many expiration strategies as we can think of and never need to subclass!  Know and use your generic delegates and it will really increase the re-usability of your classes.  In fact, any time when you are thinking of adding an abstract method and needing to provide functionality in a sub-class, if all you are doing is providing “hooks”, consider generic delegates instead.

Summary

Well, that’s the end of my “Little Wonders” series for now.  I really and sincerely hope you found something useful in at least one of these three posts.  If you did, feel free to spread it on!

I’ll leave you with 3 freebies that were too short to really devote to a section, but I so hated to leave them out!

  1. You can prefix string literals with @ so you don’t have to use escape sequences for paths, etc:
    • @”c:\downloads\data\files\d0.html” instead of “c:\\downloads\\data\\files\\d0.html”.
  2. You don’t need to create a new delegate for creating a new event handler, use the generic EventHandler:
    • public event EventHandler<MyEventArgs> OnClick;
  3. In a Windows Service Main method, you can query Environment.UserInteractive:
    • Tells you whether the application was started as a service or from command line/IDE.  You can query this bool to determine whether or not to start your service as normal, or whether to explicitly invoke OnStart() instead for debugging.  Smart application of this technique makes it easy to debug windows services in the IDE or from command line.
This article is part of the GWB Archives. Original Author: James Michael Hare

Related Posts