Bill Blogs in C# -- Effective C#

Bill Blogs in C# -- Effective C#

Created: 12/7/2016 6:58:41 PM

I’m excited to announce that the 3rd edition of “Effective C#” is coming out this month. Just in time for a Christmas gift for that developer on your list.

This is the first major milestone in a large project: I’m updating both “Effective C#” and “More Effective C#”. The first edition of “More Effective C#” was released in 2005, coinciding with the release of C# 3. A number of the items covered LINQ and related language features. The second edition of “Effective C#” came up a few years later with C# 4. The new areas were dynamic support, and the PLINQ libraries.

Then, I waited. I did not want to make more updates until Roslyn came out. The switch to the Roslyn compiler came  with C# 6.  Both books are somewhat out of date. They also aren’t organized for developers who did not start using C# with one of the earliest versions. The existing versions were organized based on the version that was current when the book was released.

I took the opportunity afforded by updating both books to reorganize the content (all 100 items in both books). I believe that Effective C#, and the upcoming edition of More Effective C# are more approachable to experienced developers whose C# experience is only with the more recent versions.

Yes, that does mean I’m currently working on updating More Effective C#. I’ll announce it here when it is ready.

You can pre-order Effective C# directly from InformIT or from Amazon.

Created: 11/11/2014 4:12:48 PM

I spent last week in Seattle / Redmond at the Microsoft MVP Summit. As is the case every year, this year’s event was primarily NDA content. I’ll be blogging about the technical content at the summit as the NDA restrictions are lifted.

However, I can talk about the experience.  The MVP summit is one of my favorite events of the entire year. I get to meet super smart people from all over the world that share the same love of software development. It’s a huge community, and I’m always amazed at the people I meet. This year was no exception.

I got to meet the folks that build Friendly, a very powerful and interesting test library for test automation. I got a great demo on the evening of the MVP Showcase event. It’s really quite impressive. The main site for their company is here: English, or Japanese.

While at the Showcase, they asked me to sign copies of my book, which has been translated into Japanese. We all posed for a picture after that:

WP_20141102_17_51_00_Pro

It was also the first time I’ve been asked to sign an electronic copy of my book. If I get a copy of the picture,I’ll post that as well.

It was a great opening to the Summit, and I’m happy to have met new people that appreciate what I’ve written. You should check out their project, it’s really cool and quite powerful.

Created: 1/25/2013 4:35:35 PM

I try not to write posts that are simply links to other posts, but I had to make an exception for this.  I was quite happy to see Scott Meyer's post on writing an effective effective book earlier this week. I received an earlier version of this advice almost a decade ago when I first worked on the proposal and outline for Effective C#. That advice, and all of Scott's additional advice and counsel made all the books I've written for the Effective series better. His guidance and advice are a key reason why the Effective Series books are so successful, and so well-received. The the authors in the series receive this advice, and receive constant feedback on the content, the form, the advice, and the style that goes into an Effective book.

The advice I got from Scott helped in many areas beyond writing that book. It has helped me become better at writing in general. I'm also better at explaining difficult concepts when I'm speaking to developers, or in meetings with other technical leaders. I remember several review comments from Scott on my first manuscript that started, “I don’t know C# very well, but this doesn’t make sense to me. Will your readers understand this?” It made me rework several explanations for greater clarity, and to be more complete.

If you're thinking of writing a book, you must read this post. It contains many nuggets of information that will help you reach your audience. You'll explain your points more clearly, and you'll justify your arguments much better. Your writing will actually accomplish its purpose.

Even if you don't plan to write a book, you should read this advice. If you work in technology, and you ever explain difficult concepts to coworkers, managers, customers, or others, this information is very useful. You'll be more effective at work, and your advice and counsel will be taken more often.

If you've enjoyed the books I've written for the Effective Series, this post gives you a glimpse at Scott's advice to make those books as useful as they've been. It’s invaluable advice. Read it. It will help you as much as it helped me.

Created: 7/25/2012 8:59:01 PM

I received a very interesting question from a reader earlier this week:

I have a question for you about Item 12 in Effective C# (2nd edition), "Prefer Member Initializers to Assignment Statements".  Here is my problem:

I recently inherited a very complicated application in which I had to find and fix a bug.  It was incredibly painful.  The application contained many classes that contained other classes that contained other classes that inherited from other classes that inherited from other classes.  I think you get the idea.  I found the member initializers particularly painful.  When code was about to create a new object, and I'd expect to step into its constructor, instead I'd end up stepping through a maze of member initializers for other classes, with no idea where I was, or why I was there, before I'd get to the constructor of the class I expected to be in.

After that experience, I swore that I would not use member initializers ever, and always initialize members in my constructors, so that when stepping through the code there would be some sense of chronological order of object creation that made sense.

Item 12 tells me to prefer member initializers.  You give 2 reasons why: to minimize the risk of omitting an initialization with multiple constructors, and to initialize variables as early in time as possible.  I guess my question is why is it important to initialize variables as early in time as possible???  I'd like to purposely delay initialization until I'm in the constructor to help debugging seem more natural, but if there is a real benefit of initializing earlier, I'd rather do that.  Are there any memory use or compiler optimization benefits to using member initializers?

This is a great question, because it does highlight language features, coding practices, and tools.

First the language features: the C# designers made the decision that variables in an object are initialized before any code in that object executes. You can initialize a variable with a field initializer, or accept the default initialization of the 0 bit pattern. That means field initializers execute before any constructor code. As I wrote in Effective C#, initializing object fields using field initializers insures that all are definitely initialized as early as possible.

I recommended initializing fields as early as possible, because it minimizes the chance of null reference exceptions. If you initialize fields before any code executes, you cannot write code that accesses those fields before you initialize the fields. The more code (even in constructors) that you may execute before initializing fields, the more likely you introduce those kinds of bugs. As code bases grow, developers may add new constructors, or add new method calls in constructors. Any of those additions can dereference unitialized fields, causing bugs. I expand on this in C# Puzzlers, where I discuss virtual method calls in constructors.

However, this coding practice can make it hard to debug.  There’s a little-known feature that really helps:  You can set breakpoints on field initializers. It can be confusing, unless you remember the order of initialization. That’s why I went into extensive detail in Effective C# on the initialization order of objects created using C# (and interacting with VB.NET, where the order is different).  It can be somewhat tricky, especially with very deep hierarchies. But, hopefully, you have to debug initialization code less often.

Finally, note that the title says “Prefer Field Initializers”. It’s not an absolute rule: some fields are much more naturally initialized using constructors. But, absent good reason to pull the code into a constructor, the field initializer is preferred.

Created: 5/6/2010 12:46:44 AM

I received a great question that relates to using exceptions to indicate contract failures. I thought it would be of general interest, so I am sharing the answer and discussion here:

I am reading your book More Effective C# and just finished Ch3, Item25, Use Exceptions to Report Method Contract Failures. It all makes good sense but I'm left wondering what to do in the case of a Data Access Object. Supposing I have the following class:
public class OrderDao
{
        public Order GetOrder(int id)
        {
                // Query database
                return order;
        }
        public bool OrderExists(int id)
        {
                // Query database
                return orderExists;
        }
}
What happens if the order is not in the database? Should the GetOrder method return null or throw an exception? We can call the OrderExists method before calling GetOrder but then that would involve up to two database queries, which could be more expensive than just calling GetOrder and handling the exception. What do you think is the best strategy for this?

He correctly realizes that he does not want to make two round trips to the database. Of course, you don’t want to use exceptions as a general flow control mechanism either.

I don’t have enough context to give a definitive answer on this sample. However, that gives me the chance to discuss why you’d make different design decisions.

It may be that this class is correct exactly as it is shown. Suppose the data model is such that any code searching for an Order does so through some other table, and that a missing id would indicate a data integrity error. If that is the scenarios for this application, the correct behavior is in the class above. A query for an order when the order ID does not exist is a data integrity error. When you encounter a data integrity error, you almost certainly want to stop stop processing more requests. Something should trigger a full check and recovery of the database.

Of course, because you asked the question, this likely isn’t your scenario. It’s easy to come up with a scenario that requires a different contract. Suppose your application is a customer service app. Customers call, and give you their order number. A customer service rep keys in the order number, and your code queries that database to find that order. There’s lots of ways that can fail without being too exceptional: a customer may give the wrong ID, a customer may hear it wrong, type it wrong, and so on. There are a lot of ways that searching for an order could fail in this scenario.

The answer is to change the contract so that one method will check the database and correctly return the record, or tell you that it doesn’t exists. Suppose that instead of GetOrder() you followed the LINQ convention and wrote GetOrderOrDefault().  Now your class (in pseudocode) looks like this:

public class OrderDao
{
        public Order GetOrderOrDefault(int id)
        {
                Order order = null;
                // Query database
                // if order is found, set order = returned value.
                // else order remains null
                return order;
        }
        public bool OrderExists(int id)
        {
                // Query database
                return orderExists;
        }
}

You are still doing only one database query, and you can translate that into a single result that returns the answer, if it is found, and completes its contract even when the sought record is not found.

What’s important about this answer is that you, as a class designer, create the contracts your class adheres to. You can write those contracts in such a way that under any reasonable condition, your methods can fulfill their contracts. In this instance, the important concern is that you do not want your users paying for extra database trips. You need to create a contract that enables your users to call your methods in the way they want, and still performs the way you want internally.

Created: 3/22/2010 5:54:48 PM

I received this feedback on the Safari site about an earlier draft of the 2nd Edition of Effective C#:

Text says: “You’ll notice that neither MyResourceHog nor DerivedResourceHog contain a finalizer. The example code I wrote does not directly contain any unmanaged resources. Therefore, a finalizer is not needed. That means the example code never calls Dispose(false). That’s the correct pattern. I take this to mean all I need is (assuming I need a finalizer):

~MyResourceHog()
{
    Dispose(false);
} “

Is that it? What should be done in dervied classes? Please elaborate on this just a bit more and also include the finalizer in the code, just comment it out, so we can see the full pattern for the base and dervied classes. Thanks!

I intentionally did not include an example where you included a finalizer. In the vast majority of cases, you won’t include a finalizer. If you types do not include unmanaged resources, you don’t ever need to add a finalizer. This is also explained in “Framework Design Guidelines”, pp319-322.  The important reason for not including a finalizer (when you don’t need one) is that the presence of a finalizer (even if you call GC.SuppressFinalization()) affects performance. If it’s not needed, its presence is a needless performance robber.

And, if you do need a finalizer, you always need to implement IDisposable. Then, your finalizer is always as simple is shown above.

I chose not to include the expanded sample because I didn’t want to create and show a sample that would lead to a bad practice.

Created: 1/29/2010 7:26:23 PM

The January Visual Studio Magazine marks the first time the C# Corner is written by Patrick Steele. I’ve bowed out after a long run with the magazine and its predecessors.

The most important part is that the C# column is in great hands. Patrick is excellent at explaining concepts, and he’s going to bring a wealth of new ideas and concepts to the magazine. I feel much better walking away from the column knowing it is in such good hands.

It was hard to walk away after so much time with VSM and its predecessors. But it was time. I’ve written on so many C# topics that I was having trouble coming up with ideas that felt new. I felt like I was covering the same ground over and over.

That got me thinking about how long it had been, and what a long, strange trip it has been.

I started as the original C++ Fundamentals columnist for Visual C++ Developers Journal in the 1990s. That was a new magazine published by TPD, for the MFC / C++ Developer. It were covering techniques to bridge the divide between 16 bit and 32 bit applications. There was this amazing new OS code-named ‘Chicago’ on the horizon.

A few  years went by. I kept covering more topics related to C++ and windows development. More MFC, ATL, language enhancements and how the Microsoft C++ compiler tracked (or didn’t track) the C++ standard.

At some point in this period, Visual C++ Developers Journal was bought by Fawcette. TPD stopped being involved.

The turn of the century brought more changes.  This amazing new .NET platform and the C# language showed up. I started writing about C#and .NET fundamentals, instead of C++. Although the change was gradual: In the beginning, I was writing 2 C++ columns for every 1 C# column. Over time that kept changing.

Next, came some initiatives to capture more of the web audience. Several of the columnists starting writing a column online (at the rate of one a week). These weren’t all tech columns. Some were more opinion, or ‘tip’ columns. That felt like quite a grind. I was constantly under deadline pressure to come up with a new idea every week. It soon got harder: The readers liked the ‘how to’ columns most. I was asked to replaces the ‘tips’ and ‘opinion’ entries with more regular columns.

I took a break and wrote a book (Effective C#, the first edition).

I wrote for a while, and then there were more changes.  Visual C++ Developers Journal merged with Visual Basic Programmers Journal to become Visual Studio Magazine. This was a challenging time to write for this magazine. The audiences for VCDJ and VBPJ were very different. And, most importantly, they were both afraid of losing content to the ‘other’ audience. C# aficionados were concerned that they’d lose coverage to the larger VB market. VB developers felt the same fear of losing coverage to the newer, and perceived to be cooler C#. That was a tough era. The editorial staff did a tremendous job to navigate a very tough set of market perceptions.

I stayed on break and wrote a second book (More Effective C#).

Then, I was approached to come back and write the C# Corner column for Visual Studio Magazine. Having finished the book, it was time to keep writing again. It was fun for a while. I was and still am impressed by the energy that 1105 media is bringing to the publication.  I had a blast over the past two years writing for a reenergized Visual Studio Magazine.

Then, while still trying to write the column, I updated Effective C#, covering C# 4.0, and other recent enhancements to the language.

I was running out of ideas for the column. Visual Studio Magazine deserves better content. That’s why I worked with Michael Desmond and the editorial team at VSM to turn over the column to Patrick. I’m glad it’s in good hands.

So what’s next?

I’m now writing content for the C# Developer Center. The cadence will be roughly once a month, and I’ll be writing on current and upcoming language features in the C# language.

Created: 1/18/2010 4:59:53 PM

As promised, here are the slides and demos from my CodeMash Talk:  Going Dynamic in C#.

Slides.

Demos.

Please note that the demos are compatible with VS2010 Beta 2. They will not load (or run) on VS2008. I believe they will be compatible with future VS2010 builds, but predicting the future is very hard.

Thanks to the CodeMash committee for letting me speak again. It’s a great experience, and I’m proud to be a small part of the conference.

Created: 12/17/2009 7:58:18 PM

In my last post, I wrote about the new items in the second edition of Effective C#, and those items that were removed to make room for the new items. Now, let’s discuss what happened to the items that I carried over from the previous edition.

Every item received a rather significant update for this new versions. However, you won’t see that from looking at the table of contents in InformIT. That’s because the advice is very similar to the earlier edition. However, the way you implement the advice has changed significantly. As I mentioned in the last post, the C# language has made many significant enhancements over the years since the first edition was published. We have many different tools at our disposal to express our designs. That means we have many new techniques that we can use to achieve the same goals of better software, and clearly communicating our designs to other developers.

In the new edition, I re-wrote all the samples to use the latest version of C#, taking advantage of all the features in C# 4.0. That does not mean I use C# 4.0 syntax in every single item. It does mean that I thought about how to express an idea using the full palette of features available in C# 4. In many cases, that meant using features available in C# 3, or even C# 2. In other cases, the samples will include some of the latest C# features. In all cases, I updated the justifications for the advice, and how to implement the goals, in the context of C# 4.0.

Even if you have no experience with earlier versions of C#, you can use the advice in the second edition. Furthermore, you can use much of the advice even if you have not updated your environment to C# 4.0, and .NET 4.0.

Created: 12/4/2009 4:38:04 PM

The 2nd edition of Effective C# is now available on Rough Cuts. With that, I’ve started to get questions via email about how I decided which items to add, and which items to drop.

It should be clear from the additional content what’s new: I added coverage of the significant C#4.0 features like dynamic invocation and named / optional parameters. New library additions like PLINQ are also covered.

It’s much harder to see how I decided which items to drop. There are 15 completely new items in the 2nd edition, so that meant finding 15 items to drop. (Several other items have the same title, but were significantly rewritten – that will be the subject of another blog post.) Here’s how I decided which items to remove:

Items that are less important now. A number of the items in the first edition discussed techniques that were much more important before generics were available. Some of these items were those that discussed boxing and unboxing, the collection classes, and the data set class. All of those techniques and libraries were far more useful in C# 1.x than in the current .NET universe.

Items that have become common practice. C# has been around for almost a decade, and the community is much more mature than it was in 2004, when Effective C# was published. Some of the items are part of the conventional wisdom now

Items that assumed your last language was C++ or Java. The early adopters of C# were developers that came from C++ (on the Windows platform) along with some developers that came from Java. That’s no longer true.  College grads (since 2002 or so) are using C# for their first professional programming experience. Others are coming from VB, Ruby, Python, or PHP. (I’m not claiming that C# is grabbing market share from all those languages; the migration happens in all directions.) It just wasn’t right to assume that every C# developer has C++ or Java experience anymore.

The poster child for dropping items is the original Item 41, where I advocated using DataSets rather than implementing IBindingList yourself. I didn’t rewrite this item because the obvious answer now is to use BindingList<T> when you need the IBindingList capability. If you were using DataSets for some other reason, pick some other generic collection type. There are many, and the options grew again in .NET 4.0. Those generic collections have better APIs (the type parameter means the compiler ensures type correctness), and better performance (boxing / unboxing doesn’t apply. It’s not often that it’s trivial to get better performance and better chances at correctness. Even in the 1.x days, I didn’t advocate using DataSets are part of a service API. That was and still is a painful choice.

There’s also been many enhancements in the .NET framework that mean there are better data solutions. LINQ, along with the query syntax pattern (See Item 36 in More Effective C#), means there are much better ways to work with data in .NET 4.0.  Chapters 4 and 5 of More Effective C# discuss these important techniques. The entity framework has matured, and is a better way to handle data transfer between layers and machine boundaries. (I still need to look more closely at the latest EF, I know some of the changes, but not all).

All in all, I’m happy that the second edition did preserve quite a bit of the original advice from the first edition. The C# language has grown, and there are better tools in the C# toolset. It was clearly time for an update that represented the changes in the C# language, the .NET framework, and the C# community at large.

Created: 7/23/2009 3:04:04 AM

A friend asked me about some issues he was having using Enumerable.Cast<T>(). In his mind, it just wasn’t working. Like so many problems, it was working correctly, just not the way he expected. It’s worth examining.

Examine this class:

             1:
          public
          class MyType
             2: {
             3:
          public String StringMember { get; set; }
             4:  
             5:
          public
          static
          implicit
          operator String(MyType aString)
             6:     {
             7:
          return aString.StringMember;
             8:     }
             9:  
            10:
          public
          static
          implicit
          operator MyType(String aString)
            11:     {
            12:
          return
          new MyType { StringMember = aString };
            13:     }
            14: }

Note:  I normally recommend against conversions, (See Item 28 in Effective C#), but that’s the key to this issue.

Consider this code (assume that GetSomeSttrings() returns a sequence of strings)

             1: var answer1 = GetSomeStrings().Cast<MyType>();
             2:
          try
        
             3: {
             4:
          foreach (var v in answer1)
             5:         Console.WriteLine(v);
             6: }
             7:
          catch (InvalidCastException)
             8: {
             9:     Console.WriteLine("Cast Failed!");
            10: }

You’d expect that GetSomeStrings().Cast<MyType>() would correctly convert each string to a MyType usingthe implicit conversion operator defined in MyType. It doesn’t, it throws an InvalidCastException.

The above code is equivalent to this construct, using a query expression:

             1: var answer3 = from MyType v in GetSomeStrings()
             2:               select v;
             3:
          try
        
             4: {
             5:
          foreach (var v in answer3)
             6:         Console.WriteLine(v);
             7: }
             8:
          catch (InvalidCastException)
             9: {
            10:     Console.WriteLine("Cast failed again");
            11: }

The type declaration on the range variable is converted to a call to Cast<MyType> by the compiler (See Item 36 in More Effective C#). Again, it throws an InvalidCastException.

Here’s one way to restructure the code so that it works:

             1: var answer2 = from v in GetSomeStrings()
             2:               select (MyType)v;
             3:
          foreach (var v in answer2)
             4:     Console.WriteLine(v);

What’s the difference? The two versions that don’t work use Cast<T>(), and the version that works includes the cast in the lambda used as the argument to Select().

And, that’s where the difference lies.

Cast<T>() Cannot access User Defined Conversions

When the compiler creates IL for Cast<T>, it can only assume the functionality in System.Object. System.Object does not contain any conversion methods, therefore, Cast<T>() does not generate any IL that might call any conversion operators.

Cast<T>() will only succeed if its argument is not derived from the target (or a type that implements the target if the target is an interface), Cast<T> fails.

On the other hand, placing the cast in the lambda for the Select clause enables the compiler to know about the conversion operators in the MyType class. That means in succeeds.

As I’ve pointed out before, I normally view Conversion operators as a code smell. On occasion, they are useful, but often they’ll cause more problems than they are worth. Here, without the conversion operators, no developer would be tempted to write the example code that didn’t work.

Of course, if I’m recommending not to use conversion operators, I should offer an alternative.  MyType already contains a read/write property to store the string property, so you can just remove the conversion operators and write either of these constructs:

             1: var answer4 = GetSomeStrings().Select(n => new MyType { StringMember = n });
             2: var answer5 = from v in GetSomeStrings()
             3:               select new MyType { StringMember = v };

Also, if you needed to, you could create a different constructor for MyType.

Created: 5/11/2009 5:54:09 PM

My last post (which was too long ago), generated question on whether I prefer the query language or the method notation for LINQ queries.

The answer is ‘yes’.  Jon Skeet mentioned this as well last January, but anything you can do with query syntax can be accomplished with method calls. (Item 36 of More Effective C# discusses is some detail how the query language operators map to method calls.)

From the standpoint of correctness, you can use either construct with no differences. That means it is a matter of style whether you choose the query expressions or the method calls.

My own preference is to use the method call syntax for simpler queries, and use the query syntax for more complex query operations.

For example, I would use the method call syntax below over the query syntax:

             1:
          int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
             2: var smallNumbers = from n in numbers
             3:
          where n < 5
             4:                    select n;
             5:  
             6: var smallNumbers2 = numbers.Where((n) => n < 5);

However, once a query gets sufficiently complex, I believe the query syntax is more readable:

             1:
          int[] odds = { 1, 3, 5, 7 };
             2:
          int[] evens = { 2, 4, 6, 8 };
             3: var values = from oddNumber in odds
             4:             from evenNumber in evens
             5:
          where oddNumber > evenNumber
             6:             select new { oddNumber, evenNumber, 
             7:             Sum = oddNumber + evenNumber };
             8:  
             9: var values2 = odds.SelectMany(oddNumber => evens,
            10:     (oddNumber, evenNumber) =>
            11:
          new { oddNumber, evenNumber })
            12:     .Where(pair => pair.oddNumber > pair.evenNumber).
            13:     Select(pair => new { 
            14:         pair.oddNumber, 
            15:         pair.evenNumber, 
            16:         Sum = pair.oddNumber + pair.evenNumber });

In my opinion, for more complex queries, the query language produces a much more readable construct. However, on simpler queries, the method calls are easier to understand.

I like Jon’s comment: “next time you’re writing a query expression, take a look at it afterwards – it it’s simple, try writing it without the extra syntactic sugar.” (from the post referenced above).

Created: 12/12/2008 8:57:00 PM

More Effective C# was one of the better selling books at PDC, which triggered Alan Ashcraft to sit down and chat with me about C#, writing, helping customers, and being a general nerdy person.

The full interview is here: http://dotnet.dzone.com/articles/net-author-qa-bill-wagner-more

And, the interview contains links for a download of a portion of Chapter 3 in More Effective C#.

Created: 10/28/2008 6:06:00 AM

Today, the fine folks at InformIT posted another item from More Effective C# for you to learn more about the style and the content from the book:

Item 29:  Enhance Constructed Generic Types with Extension Methods

If you have questions about the content, come by The Ann Arbor Computing Society (AACS) on Wed Nov 5th.  That's one of the topics I'll be discussing before signing books at Borders.

Update:  That would be the downtown Ann Arbor Borders, on Liberty.

Created: 10/26/2008 5:00:10 PM

A little while ago, I did a DNR TV on C# 3.0. During that, I talked about preserving null semantics when  you write extension methods.  I made the point that you should never test if the first parameter of an extension method is null. That’s because it breaks the semantics of member methods, which is what extension methods appear to be from the calling spot.

For example, this bit of code would throw a null reference exception:

 

SomeType foo = null;

foo.SomeMethod();

 

However, if SomeMethod were actually implemented like this you’d lose error information and let possible error conditions go undetected:

public static Result SomeMethod(this SomeType thing)

{

    if (thing == null)

        return null;

    // etc.

}

 

Clearly that’s bad.  Well, recently one of the folks like saw this DNR TV episode asked me this question:

What is your opinion of checking for null on the first parameter and then throwing an ArgumentNullException?

public static void SendMail(this IEnumerable<Person>

    sequence)
{
    if(sequence == null)
        throw new ArgumentNullException…;
}

That also changes the semantics of the method modulo an instance method. It is more subtle, but it has still changed.

As I said above, de-referencing null throws a NullReferenceException. the sample in the question above throws an ArgumentNullException.

That’s semantically different.

Client code that wants to examine and recover from that coding mistake will be broken. 

Important side bar point: I’m not advocating catching NullReferenceExceptions as a program logic technique (In fact, I think that’s a bad idea).

Even though I don’t want client developers to control program logic by chcking for NullReferenceException, I should ensure that my code obeys the existing semantics.

Well, suppose you changed the SendMail method as follows so it does follow the normal semantics:

public static void SendMail(this IEnumerable<Person>

    sequence)
{
    if(sequence == null)
        throw new NullReferenceException…;
}

Well, now it does obey the semantics of an instance method. That’s good.

However, you’ve now written extra lines of code that don’t do anything useful. If you removed the check, the code would behave exactly the same. As a general rule, I don’t like to write code that doesn’t do anything. (See gratuitous default constructors for an example). 

That’s why I make the practice of not checking null on the first parameter of extension methods.  I don’t write code, and it works correctly.

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.