28th January 2010
Some time ago I blogged about a number of areas of the .NET Framework that people really should be both aware of and actively using. This was driven by working on existing codebases that appeared to show a lack of knowledge of some fundamental aspects of the framework and associated languages.
This time around the points aren't necessarily as small and 'obvious' as the items in the original list. However they are powerful aspects of C# or VB.NET that are useful to know as a beginner and can even seem to slip people by who have been working with .NET for some time.
An early, obvious one, Extension methods have been available in the .NET framework for a while now. Essentially they can be used in place of a static method that performs some action on it's first parameter - using additional parameters if necessary.
After creation and referencing they manifest to the developer as instance methods on the type being 'extended' with full intellisense support (this syntactic sugar is actually just the same as a static call behind the scenes).
public static class StringExtensions { // Notice the 'this' keyword before the first parameter to signify that this // is an extension method for string public static int ToInt(this string @string, int defaultValue) { int value; return int.TryParse(@string, out value) ? value : defaultValue; } public static int? ToNullableInt(this string @string, int? defaultValue) { int value; return int.TryParse(@string, out value) ? value : defaultValue; } } // Call style string a = "5"; int? b = a.ToNullableInt(null); // 'this' parameter is omitted
There has been a lot of discussion surrounding the acceptable usage of extension methods (which many people regard as a code smell outside of linq). However, outside of fluent interfaces, they can be extremely useful at simply removing repetition. In the example above we can see how the minor process of parsing a string into an integer can be extracted away from wherever it is needed in the codebase into an extension method for string. This then allows the logic of an application to be more concise as the non-business logic related/mundane tasks are hidden away.
The key difference for me, with these small applications of extension methods, is that they are not used in areas where the functionality could possibly be swapped out in the future. In these cases a more Object Oriented Polymorphic approach would be favoured.
Some time ago, when I wrote about Date Formatting in XML/XSLT I made reference to the following sanity check before embarking on any coding endeavour:
Does this new piece of functionality fit within the framework somewhere already?
The reasoning behind this is both an issue of maintenance and expectation. If a project closely works alongside the extensibility points of the framework new developers can have an expectation that logic is implemented in a way that fits with their pre-existing knowledge. This includes general library design as well as how new functionality is created.
string.Format(new BritishDateTimeFormatter(), "{0:ddx}", dt);
The British date formatting example shows an implementation of an IFormatProvider, ICustomFormatter to add british suffix ('th', 'st', 'rd') formatting to dates using the 'x' character. The issue here is that any object could have been custom made to provide methods for british date formatting. However by implementing a pre-existing interface (IFormatProvider) the code can be used with the string.format method and can be reused by any other library that has decided to use the 'built in' IFormatProvider.
Many similar interfaces exist (IConvertible, IComparable, IFormattable, IEquatable etc) as well as the provider model for things like membership etc. The point is to look for these 'fits' within the framework before just starting from scratch.
To continue the idea of building to the framework rather than just with it lets take a look at a quick example of overloading operators. The general pattern is that you implement a static method within a Type definition that uses the 'operator' keyword and symbol/TypeName to identify itself as an implementation of an operator.
This allows the specification of what happens when you do MyCustomTypeInstance + MyCustomTypeInstance or (MyCustomTypeInstance)myStringValue. Available operators include ++, --, !, +, -, *, /, %, ==, !=, >, <, &, |, ^, <<, >>, >=, and <= as well as conversions between types.
One of the canonical example's of this for me is the 'Cycle' example as discussed by some of the Microsoft Literature whereby the + operator is overloaded for a custom Cycle type. This allows the Cycle to control addition to an inner integer value and cycle back to the beginning of a range when it is added to e.g. a Cycle is created with min 1 and max 5. When 1 is added to a cycle with value 5 the value becomes 1 instead of 6.
Another example below shows how custom conversion can also be implemented as operators on a class:
public MyClass { ... public static implicit operator int(MyClass arg) { return arg.Id; } } // Calling example MyClass myClassInstance = new myClassInstance(5); int i = myClassInstance;
In this case an integer can be set directly from the custom instance (which could be a value that is calculated or even private and not exposed in any other way).
This kinda of approach can be very powerful. However the decision to use them should take into account the slightly hidden nature of them. For example you could override the cast to boolean operator to do validation, but doing so strips you of the ability to expose a clearly named 'Validate' method (or you end up doing both leading to inconsistent usage of the two in consuming libraries).
As developers of .NET web applications we often find ourselves using the Global.asax file to specify actions to undertake on particular events. The only issue here is that to reuse this functionality you need to merge pre-existing global.asax files between projects. Additionally they are not particularly well defined. That is to say, that you can't look at the name of it and get a feel for what it does. However, if we use implementations of IHttpModule instead, they can be encapsulated. For example you might have an AuthenticationModule or an ErrorModule as below:
public class ErrorModule : IHttpModule { ... public void Init(HttpApplication application) { application.Error += new EventHandler(Application_Error); } public void Application_Error(object sender, EventArgs e) { ... logger.LogError(string.format("Unhandled exception: {0}", exception)); } }
<!-- Web.config extract --> <system.webServer> <add name="ErrorModule" type="Cargowire.Common.Web.ErrorModule, Cargowire.Common.Web" /> </modules>
As you can see the Application_Error event usually found in global.asax is part of the IHttpModule specification allowing multiple different event handlers to listen for the same events rather than clogging the global.asax with disperate concerns.
When a url is requested the code that handles generating a response is an HttpHandler (System.Web.StaticFileHandler, System.Web.Mvc.MvcHandler etc). Custom handlers can also be created, implementing IHttpHandler and registered in the web.config they can respond to requests to a specified path. They are particularly useful when no real response is required or if the response is plain text, with that added benefit that they incur far less setup (in terms of wiring of post back, session etc that happens on normal page loads).
A common problem encountered in systems with prolonged data entry is the possibility that the session times out between edits. To keep a session alive some simple javascript can be written to poll the server to keep alive the user session. There is no real response needed and definitely no need for a full page request process to begin...
/// The IRequiresSessionState does nothing but mark this handler as requiring the Session /// context to be available to the handler. This can be omitted if session is not required public class Heartbeat : IHttpHandler, IRequiresSessionState { public readonly bool IsReusable() { get { return false; } } public void ProcessRequest(HttpContext context) context.Response.ContentType = "text/plain" context.Session("keepalive") = DateTime.Now.Ticks context.Response.Write(context.Session("keepalive")) } }
The above can be implemented as a code file and then registered in the web.config or as a .ashx file in your web project.
Another recent example where using an IHttpHandler can make sense is as a responder to an AJAX auto-complete script. There is no need for session, no full page output, no separate use case, the functionality only exists for javascript to call it and receive a json object containing suggestions for the input field. So there is no need to implement this as a complete page or controller/view - Instead just a light weight handler.
It's important to note these lists aren't meant as a teaching aide for learning .NET from scratch nor does usage of any of the above immediately make you a better programmer. Extensive knowledge of a language and framework is beneficial but not without a grounding in how to utilise it effectively and in a considerate manner as regards maintainability, reuse and handover to new devs.
Hopefully this list has highlighted some areas for further reading. More info can be found through a plethora of resources including those mentionned in my 'useful for a .NET dev' post.
All article content is licenced under a Creative Commons Attribution-Noncommercial Licence.