extension methods, nulls, namespaces and precedence in c#

5

Click here to load reader

Upload: paul-houle

Post on 10-May-2015

973 views

Category:

Technology


0 download

DESCRIPTION

Extension methods are the most controversial feature that Microsoft has introduced in C# 3.0. Introduced to support the LINQ query framework, extension methods make it possible to define new methods for existing classes. Although extension methods can greatly simplify code that uses them, many are concerned that they could transform C# into something that programmers find unrecognizable, or that C#’s namespace mechanisms are inadequate for managing large systems that use extension methods. Adoption of the LINQ framework, however, means that extension methods are here to stay, and that .net programmers need to understand how to use them effectively, and, in particular, how extension methods are different from regular methods.

TRANSCRIPT

Page 1: Extension methods, nulls, namespaces and precedence in c#

Generation 5 » Extension Methods, Nulls, Namespaces and Precedence in C#

http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/[1/12/2014 8:23:49 PM]

Extension Methods, Nulls, Namespaces and Precedence inC#Introduction

Extension methods are the most controversial feature that Microsoft has introduced inC# 3.0. Introduced to support the LINQ query framework, extension methods makeit possible to define new methods for existing classes.

Although extension methods can greatly simplify code that uses them, many areconcerned that they could transform C# into something that programmers findunrecognizable, or that C#’s namespace mechanisms are inadequate for managinglarge systems that use extension methods. Adoption of the LINQ framework, however, means that extension methods are here to stay, and that .netprogrammers need to understand how to use them effectively, and, in particular, how extension methods are different from regular methods.

This article discusses three ways in which extension methods differ from regularmethods:

1. Extension methods can be called on null objects without throwing an exception2. Extension methods cannot be called inside of a subclass without the use of ‘this’3. The precedence rules for extension methods

The Menace of Null Values

The treatment of null values is one of the major weaknesses of today’s generation oflanguages. Although C# makes it possible to make nullable versions of value types, such as int? and guid?, there’s nothing in C# or Java like the “NOT NULL” declarationin SQL. As a result, handling nulls is a significant burden to writing correct code. Consider the simple case where you want to write[01] someObject.DoSomething();

(where DoSomething is an ordinary instance method) When I type something likethis, Resharper often highlights the line of code to warn me that someObject mightbe null. In some cases I might be confident that it never will, but if there is anychange that it will be null, I’ll need to write something like[02] if(someObject!=null) {[03] someObject.DoSomething();[04] }

or maybe[05] if(someObject==null)[06] return;[07] someObject.DoSomething();

Alternatively I could accepted that an exception could be thrown by the invocationand decide to catch it (or not catch it) elsewhere in the application. In two cases outof three, one line of code gets bulked up to three. Worse than that, I need to makea decision at that point about what to when there’s an error condition — eachdecision is a case where somebody can make the wrong decision. Even if codersmake the wrong decision 5% of the time, that would be 50 time bombs in your codefor every 1000 method invocations. (Oliver Steele works out a particularly outrageousbut common case where it takes 10 lines of null-checking code to protect 1 line ofworking code.)

Extension Methods Can Accept Null Values

What does this have to do with extension methods?

Unlike ordinary instance methods, extension methods do not automatically throw an

Search for:

ArchivesJune 2012 (1)August 2010 (1)May 2010 (1)June 2009 (2)April 2009 (1)March 2009 (1)February 2009 (3)January 2009 (3)November 2008 (1)August 2008 (2)July 2008 (5)June 2008 (5)May 2008 (2)April 2008 (6)March 2008 (8)June 2006 (1)February 2006 (1)

CategoriesAJAX (2)Asynchronous Communications (16)Biology (1)Books (1)Design (1)Distributed (1)Exceptions (2)Functional Programming (1)GIS (1)Ithaca (1)Japan (1)Math (1)Media (3)Nature (1)Semantic Web (3)Tools (28)

CRUD (1)Dot Net (17)Freebase (2)GWT (9)Java (7)Linq (2)PHP (6)Server Frameworks (1)Silverlight (12)SQL (5)

Uncategorized (1)Web (2)

Analytics (1)

Subscribe to our RSS Feed | About Us

Page 2: Extension methods, nulls, namespaces and precedence in c#

Generation 5 » Extension Methods, Nulls, Namespaces and Precedence in C#

http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/[1/12/2014 8:23:49 PM]

exception if you call them on a null-valued object. Depending on your point of view, this can be (i) a gotcha, or (ii) a useful tool for simplifying your code. Here’s a littleexample:[08] namespace ExtensionMethodTest {[09][10] static class ObjectExtension {[11] static public bool IsNull(this object o) {[12] return o == null;[13] }[14] }[15][16] class Program {[17] static void Main(string[] args) {[18] String s1 = "hello";[19] Console.WriteLine(s1.IsNull());[20] String s2 = null;[21] Console.WriteLine(s2.IsNull());[22] Console.WriteLine(s2.ToUpper());[23] }[24] }[25] }

This example does something a bit bold: it attaches an extension method to object, adding an extenson method to every object in the system. This method, object.IsNull() returns true if object is null and false if it isn’t. Some people might seethis as a nice example of syntactic sugar, others may see it as reckless. What’simportant is that it works: if you run this program from the command line, line [21]will print ‘true’, while line [22], which uses an ordinary method, will throw aNullReferenceException.

Events and Extension Methods for Delegates

Chris Brandsma works out a practical example of how extension methods can be usedto fix a broken and dangerous API. That is, the event handling mechanismcommonly used in C#:[26] public eventEventHandler<EventArgs> OnLoadData;[27] ...[28] OnLoadData += SomeEventHandler;[29] ...[30] OnLoadData(this, argument);

OnLoadData is a MulticastDelegate. You can attach an unlimited number of realdelegates to it. The sample above works great if you attach at least one delegate, but it fails with a NullReferenceException if you don’t. Perhaps this isn’t a problem foryou, because you’re smart and you write[31] if (OnLoadData==null) {[32] OnLoadData(this,argument)[33] }

Unfortunately, there are two little problems with that. First, none of us program in avacuum, so many of us will end up having to maintain or use objects wheresomebody forgot to include a null check. Secondly, the example between lines [31]and [33] isn’t thread safe. It’s possible that a method can be removed fromOnLoadData between the time of the null check and the call!

It turns out that extension methods can be added to delegates, so Chris created areally nice extension method called Fire() that encapsulates the error check codebetween 31-33. Now you can just write the code you wanted to write:[34] OnLoadData.Fire(this,argument);

and be confident that knowledge about threads and quirks of the type system isembedded in an extension method.

You must use this to access an extension method inside a subclass

Suppose you’re building a Silverlight application and you’d like your team to have animportant method that incorporates something tricky on their fingertips. Forinstance, suppose you’re implementing error handling in an event handler that’sresponding to a user-initiated event or an async callback. You can always write[35] if(... something wrong...) {[36] ... several lines of code to display dialog box ...[37] return;[38] }

But this is something that (i) programmers don’t want to do to begin with, (ii) thatprogrammers will have to do tens or hundreds of times, and (iii) isn’t going to be inthe main line of testing. It’s a quality problem waiting to happen. It’s imperative, therefore, to reduce the amount of code to do the right thing as much as possible…

Page 3: Extension methods, nulls, namespaces and precedence in c#

Generation 5 » Extension Methods, Nulls, Namespaces and Precedence in C#

http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/[1/12/2014 8:23:49 PM]

To make it easier to do the right thing than to do the wrong thing. It’s tempting todefine an extension method like:[39] public static void ErrorDialog(this UserControl c, string message) {[40] throw new ErrorMessageException(message);[41] }

and catch the ErrorMessageException in the global error handler. (The “method thatdoesn’t return” is effective, because it avoids the need to repeat the return, whichoccassionaly seems to vanish when people write repetitive error handling code.) You’d think that this simplifies the code inside the UserControls you write to:[42] if (... something wrong...) {[43] ErrorDialog(...);[44] }

But it turns out that line [43] doesn’t actually work, and you need to write[45] if (... something wrong...) {[46] this.ErrorDialog(...);[47] }

in which case you might as well use an ordinary static method on a helper class.

What’s wrong with extension methods?

I’ve seen two arguments against extension methods: (i) extension methods couldmake code hard to understand (and hence maintain) and (ii) extension methods arevulnerable to namespace conflicts. I think (i) is a specious argument, but (ii) isserious.

I think (i) splits into two directions. First there’s the practical problem that aprogrammer is going to see some code like[48] String s="[email protected]";[49] if (s.IsValidEmailAddress()) {[50] ... do something ...[51] }

and wonder where the heck IsValidEmailAddress() comes from, where it’sdocumented, and so forth. Practically, Visual Studio understands extension methodswell, so a user that clicks on “Go To Definition” is going to get a quick answer.

Going further, however, one can imagine that extension methods could transform C#unrecognizably:  I think of a friend of mine who,  in the 1980′s,  liked FORTRAN betterthan C, and abused preprocessor macros so he could write C code that looked likeFORTRAN. This is connected with a fear of lambda expressions, and other featuresthat derive from functional programming. For instance, that beginning programmersjust won’t get it.

We’ll see how it all works out, but I think that new features in C# are going to helpthe language evolve in a way more like jquery and prototype have transformedjavascript. Microsoft is bringing concepts that have been locked in the ivory tower fordecades into the mainstream: all programming languages are going to benefit in thelong term.

Extension methods, precedence and namespaces

Here’s the killer.

I can make extension methods available by just adding a namespace to my .cs filewith a using directive. The compiler scans the namespace for extension methods instatic classes, and makes them available. Pretty easy, right? Well, what happens iftwo extension methods with the same name get declared in two namespaces whichget included in the same file? What if we define an extension method on class A, butthere’s a conventional method with the same name on class B? What if file One.csuses namesspace C, and Two.cs uses namespace D, so that ThisExtensionMethodmeans something different in One.cs and Two.cs?

There are real problems in how extension methods interact with namespaces. Theseproblems aren’t as fatal as namespace conflicts were in C (and C++ beforenamespaces), but they are for real.

One answer is to avoid the use of extension methods entirely, but that causes theloss of the benefits. Anyone who uses extension methods should take a close look atthe C# version 3.0 specification and think about how precedence rules effect theirwork:

Page 4: Extension methods, nulls, namespaces and precedence in c#

Generation 5 » Extension Methods, Nulls, Namespaces and Precedence in C#

http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/[1/12/2014 8:23:49 PM]

Comments (1)

Login

(i) Instance methods take precedence over extension methods. The definition of aninstance method makes extension methods with the same name inaccessable. Thishappens at the level of methods, not method groups, so two methods with the samename but different signatures can be handled by an extension method and instancemethod respectively.(ii) Once the compiler tries extension methods, processing works backwards from theclosest enclosing namespace declaration outward, trying extension methods definedin using groups.(iii) The compiler throws an error when there are two or more extension methods thatare candidates for a spot.

Matt Manela demonstrates an interesting example on the MSDN forums. With threeexamples, he demonstrates that the existence of an instance method (that overridesboth extension methods) will suppress the generation of an error message about aconflict between extension methods. This indicates that potentially conflictingextension methods in two namespaces will only cause an error if an attempt is madeto use them.

Mitigating Namespace Conflicts

Overall, conflicts between extension methods in different namespaces will not resultin catastrophic consequences:

1. The compiler raises an error if there is any ambiguity as to which extensionmethod to apply at a particular invocation — code won’t silently change behaviorupon adding a new namespace in a using directive.

2. The compiler does not throw an error if potentially conflicting extension methodsare declared in two different namespaces including in distinct using directives ifthose extension methods are not used — therefore, conflicting extensionmethods won’t automatically prevent you from using any namespaces youchoose.

3. If there is a conflict, either between two extension methods or an extensionmethod and an instance methods, you can always call a specific extensionmethod like an ordinary static example. For instance, in the case above:

ObjectExtension.IsNull(someObject);

You won’t end up in a situation where an extension method becomes unavailablebecause of a conflict — you’ll just be forced to use an uglier syntax. I do see two realrisks:

1. You can end up using an extension method that you don’t expect if you’re notkeeping track of which using directives are in your file, and

2. An instance method can silently shadow an extension method. A change in thedefinition of a method could cause the behavior of a (former) extension methodcal to change in a suprising way. On the other hand, this could be a usefulbehavior if you’d like a subclass to override a behavior defined in an extensionmethod.

A common bit of advice that I’ve seen circulating is that extension methods should bedefined in separate namespaces, so that it would be possible to include or not includeextension methods associated with a namespace to avoid conflicts. I think this isbased on superstition, for, as we’ve seen, conflicting extension methods do notpreclude the use of two namespaces; this advice is certainly not followed in theSystem.Linq namespace, which defines a number of valuable extension methods inthe System.Linq.Enumerable static class.

Conclusion

We’re still learning how to use extension methods effectively. Although extensionmethods have great promise, they’re difference from ordinary instance methods in anumber of ways. Some of these, like the difference in null handling, are minor, andcould potentially be put to advantage. Others, such as the interaction withnamespaces in large projects, are more challenging. It’s time to start building onour experiences to develop effective patterns for using extension methods.

Paul Houle on July 3rd 2008 in Dot Net

Comment (1)

Page 5: Extension methods, nulls, namespaces and precedence in c#

Generation 5 » Extension Methods, Nulls, Namespaces and Precedence in C#

http://gen5.info/q/2008/07/03/extension-methods-nulls-namespaces-and-precedence-in-c/[1/12/2014 8:23:49 PM]

ecards 0

Comment as a Guest, or login:

Displayed next to your comments. Not displayed publicly. If you have a website, link to it here.

Sort by: Date Rating Last Activity

· 268 weeks ago

Post a new comment

Subscribe to None

Copyright © 2013 Generation 5. WordPress Theme design.

Nice article. But what I'm not clear on is what's the difference between:

1) adding an extension method foobar for class A

2) adding a method foobar to a partial class A

I get the semantic differences like null checking, but there must be a more fundamental difference i'mmissing...

Reply

Name Email Website (optional)

Submit Comment