Catch up on stories from the past week (and beyond) at the Slashdot story archive


Forgot your password?
Programming Books Media Book Reviews IT Technology

Effective C# 233

Jim Holmes writes "I'm new to the .NET environment and have been looking for solid books in the same class as McConnell's Code Complete, 2nd ed., or Kernhigan and Pike's The Practice of Programming. Those books, to me, are must-haves on any serious developer's bookshelf, but while they're terrific books, they're general in nature. Bill Wagner's book Effective C# is a great companion to those books because it's specific to C# and hits hard the implementation details of working in that language. (Disclaimers: 1) I got this book for free from Addison-Wesley as a regular giveaway for our .NET Developers Group. 2) I attempted to get SRT Solutions, the author's consulting company, involved in a software development project several years ago. The project tanked due to customer constraints and other business issues not related in any way to Wagner or his company. End Disclaimers.)" Read on for the rest of Holmes's review.
Effective C#: 50 Specific Ways to Improve Your C#
author Bill Wagner
pages 336
publisher Addison Wesley
rating 9
reviewer Jim Holmes
ISBN 0321245660
summary Must-have addition to any serious C# developer's bookshelf

If you're interested in, or currently working with, .NET and are tempted to skip past this book as Just Another C# Reference Book, think again. Wagner's book is a great resource because it covers concepts which run across the entire .NET Framework regardless of which language you're working with. While this book focuses on C#, VB.NET developers can benefit from some of the text within as well.

I also think this book speaks to a wide range of readers. Seasoned developers will blow through this content, fine-tuning their coding methods or starting new ones. Wagner specifically points out how practices experienced C++ developers may use aren't good practices in C#, such as avoiding function call overhead by writing longer C# methods with more convoluted loops. More on that later.

New developers also can greatly benefit from this book by using it to properly form development habits early in their careers. Examples of this might include following Wagner's recommendations for safe casting, strong use of interfaces, and knowledgeable resource management.

Wagner's writing style is clear and concise. He occasionally comes across as brusque, or as writing only to experienced developers ("I wouldn't write code like this and neither would you."), but those instances are few and far between. The rest of the book's voice is terrific. More important is the weight of Wagner's knowledge and experience.

One real drawback is a large number of typographical errors, sometimes several per chapter. Some sentences are missing content, and there are a large number of run-together words. These errors don't take away from the material, but it's an annoyance all the same. I would have expected better proofreaders at AW.

The book is well organized into six chapters, each hitting a specific area in C#. Within each chapter, Wagner covers six to ten items, each item focusing on one specific "minitopic," as Wagner calls them. Each item includes code snippets to demonstrate recommended approaches. Few of Wagner's snippets will function as standalone programs, but this is an advantage, as I see it. The book focuses on tight, specific examples, rather than weighing itself down with pages of extraneous fluff.

Often Wagner's recommended approach is contrasted against bad practices, or practices which might be optimal in other languages but work poorly in C#. An example of this would be Chapter 4's Item 31: "Prefer Small, Simple Functions," where Wagner shows how smaller functions are generally more efficient than larger functions with complex loops. This probably confounds experienced C++ developers, but it's a prime example of how valuable this book is. Wagner shows that .NET's Just-In-Time compiler pays less cost when calling functions than it does trying to wade through convoluted loop logic. His recommendation? Write "the clearest code you can create. Let the JIT compiler do the rest."

Chapter 1, "C# Language Elements", hits hard the topics "you must remember every day when you write C# code." This chapter discusses issues central to C#'s syntax, implementation and optimization. Wagner talks about basic Object Oriented concepts such as hiding class data members behind Properties (.NET's common access methods/fields via gets and sets), and why it's important to implement a ToString() method. Basic software engineering topics are also covered, like why it's important to differentiate between value and reference data types -- and the pitfalls of failing to do so. This chapter also thrashes out coverage on deep C# concepts like why developers should use foreach loops and why the GetHashCode() method will "practically always get you in trouble."

Chapter 2, ".NET Resource Management", has a lot of text on general patterns for constructing optimal code. Wagner's in-depth knowledge of the .NET Framework's underpinnings really shows through here. There's a very clear discussion of the performance ramifications of boxing (wrapping value type data into an object for method parameters) and unboxing. Minimizing extra garbage (unnecessary objects) and easing resource clean up via standard dispose patterns are also covered. This chapter's critical to ensuring you understand what's going on with resources in your .NET application.

Chapter 3, "Expressing Designs with C#", looks at object-oriented design in C#. While the discussion's specific to C#, there's a lot of great, practical information which applies to any object oriented development. Wagner gives some great examples with backup discussion regarding preferring the use of interfaces over inheritance and why it's a cleaner solution. (Java programmers who've read Alan Holub's "Why extends is Evil" in JavaWorld would enjoy this section.) There's also great treatment of using delegates for callbacks, and events for outgoing interfaces. Wagner also points out more pitfalls in a reference data type language: returning references to internal class objects via a read-only property (getter for Java folks).

Chapter 4, "Creating Binary Components", shows what critical topics you have to consider when creating even a moderately complex system for deployment. Wagner exposes some terrific details on how smaller is better when developing .NET assemblies for deployment. He also discusses why it's best to limit a class's exposure through public scope since this ends up advertising too much of your class's internals to potential users of that class. Wagner ties this back to interface discussions in earlier portions of the book, and makes a good case in this section for bad scope's impact on deployment.

Chapter 5, "Working with the Framework", delves into the .NET Framework Class Library. The FCL is a huge library and Wagner's insistent that too many developers are writing custom code for functionality which already exists in the FCL. This section helps to avoid having "developers reinvent the wheel." There are very useful discussions on using .NET runtime diagnostics, .NET's validation capabilities, and standard configuration mechanisms. Wagner also shows why .NET's reflection capability (one component dynamically discovering another component's capabilities at runtime) can be overused - but he also shows how to best use it in the appropriate cases.

Chapter 6, "Miscellaneous", is the catch-all section. Security and exceptions are covered here, as is the pain of working with COM interoperability - and why you should avoid it if at all possible. Just as importantly, Wagner points to several tools which should be in any C# developer's belt. He also identifies terrific resources available online.

What makes this book so useful is that Wagner constantly talks about the reasons behind why specific choices in C# should be made. For example, in Item 3, "Prefer the as and is Operator to Casts" Wagner moves through the rationale of why a developer should (when possible) avoid casting in C# and use the as and is operators instead. Casting can lead to headaches with data loss when casting a long data type to an integer one, or more headaches with the extra lines of code to ensure the cast was to a proper type. Sure, casts are sometimes necessary, and it's another value point for this book that Wagner gives clear examples of when his techniques don't apply -- and he also shows recommended alternatives for those cases.

It's just this kind of discussion from an experienced developer that makes this book so valuable. Good developers need to understand the ramifications of choices they make designing and implementing a system. Wagner's book is outstanding for exactly this kind of detailed, clear exposition.

An additional bonus: Wagner has a blog dedicated to discussion of items from his book. Erata are also listed there. See Bill Wagner's Effective C# blog.

The bottom line: this book really is a critical addition to a serious C# or .NET developer's bookshelf. It deserves a place right alongside books from McConnell, Macguire, Kernighan and Pike.

You can purchase Effective C#: 50 Specific Ways to Improve Your C# from Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.

This discussion has been archived. No new comments can be posted.

Effective C#

Comments Filter:
  • by DanielMarkham ( 765899 ) on Tuesday June 28, 2005 @06:02PM (#12936269) Homepage
    " the same class as Code Complete"
    But do we really need a "programming good C#" book? Isn't good programming all about, well, good programming? If I remember Code Complete correctly, it used pascal and C, I think. It definitely was one of the best books I've read, but how many times can you say the same thing over and over again?
    Languages come and go. But good coding techniques don't dependent on a certain vendor or technology.
    Maybe this is a good book if you don't know much of any programming language and want to pick up C#. Speaking as a C# developer who does Java, C, C++, and VB, I just read some of the rags and jumped in. Then when I wanted to do something else, like create a custom web control, I got a book in C#. Presto/Bingo, I'm coding in C#. OOP as a concept is going to have similar constructs, no matter what the language, right?
    Sorry for the rant. It's probably a great book. I just don't understand how good coding practice is dependent on the flavor-of-the-week. Perhaps in his comparisons the reviewer does a disservice to the intent of the work.
    • by cheide ( 731641 ) <> on Tuesday June 28, 2005 @06:16PM (#12936402)
      The principles may be the same, but the details can differ greatly when it comes down to the specific syntax and behaviour of operations.

      Someone may be an expert at high-level OO design, but when it comes to programming in C++ specifically, he might not know about things like the utility of auto_ptr, that it's a bad idea to throw an exception from a destructor, why destructors should often be virtual, dangerous cases where an unexpected temporary object might get created and changed instead of the intended one, etc... That was where the value of the Effective C++ books was for me.
      • I completely agree.
        C++ is a high-wire act without a net, no doubt. But more "polished" lanugages, like Java and C# keep the sharp objects away from the developers. Some of those issues you mention are truly gnarly -- and you can get in a world of trouble with C++ code. You can still cut your foot off with Java, but you have to saw at it a little more. My two cents only.

        Can chickesn swim? Find out now! []
    • > But do we really need a "programming good C#" book? Isn't good programming all about, well, good programming?

      And knowing the language. Sometimes there's idioms in a language that just aren't obvious. Like the use of "explicit" to prevent C++ from surprise autocasts, or what const correctness really means and how to avoid breaking it. Or when to explicitly null references in Java to get them gc'd, and when it hurts performance (this idiom changed when Java's gc algorithm changed).

      C# no doubt has al
    • There are always some very specific language features, and more important, pitfalls. For instance, as a Java developer I was astounded that you still need to explicitely mark a method "virtual" for it to be virtual (this is probably because it makes porting from c++ easier).

      On the good side of things you have things like assemblies, the checked and override keyword, meta-data and things like that. These are pretty language specific, and you would need to learn them before becoming a moderate or expert pro

      • For instance, as a Java developer I was astounded that you still need to explicitely mark a method "virtual" for it to be virtual

        Well, if you found that astounding, you probably need to get out more :).

        Seriously, it's more of a mundane language decision than something to be astounded about. Coming from C++, when I read that Java methods were all virtual, I thought, "Ok, I see what they're doing there." But by no stretch of the imagination did it astound me.

        (this is probably because it makes

        • Hmm...replying to myself...after a few minutes of background brain actitivy, my mind has just piped up and decided that I misinterpreted your post completely, owlstead. So ignore the second half of my post as it makes no sense :-).

          Well, it makes sense on some level, but it's not relevant to the topic...for some reason my mind had decided that the thread had got onto Java/C++ differences. Must sleep.
    • Now, I'm not saying the above book is good (haven't read it, probably won't), but I do see the value of a book telling you about the best practices in the particular language you're interested in.

      You know, I would venture to say not all programming concepts are necessarily always universal. That's because programming languages are abstractions, and abstractions can vary vastly.

      Take an elementary operation: You might say a for loop is a for loop, but in languages like LISP we tend to use recursion.

      In MATL
      • I thought the quote looked familiar!

        Alas, no matter how smart programmers think themselves today, it's incredible to see how many people can't compute longhand with a great deal of speed and accuracy. Spelling, grammar, and punctuation are considerably worse, but without their hardware, most are pretty weak all of the way around.
    • On the other hand, if you're new enough to programming to need to read this book, perhaps you're only middling competent in 2 languages which are likely to be java and c# and trying to read and understand the techniques being presented in a language you don't know is just heaping on unnecessary difficulty.
    • by zhiwenchong ( 155773 ) on Tuesday June 28, 2005 @07:11PM (#12936835)
      Take a look at this:
      Sapir-Whorf and programming languages []
      • Thanks. Excellent article. I would prefer to disagree, however. There is a natural affination, once one begins "thinking" in a certain language to solve problems certain ways. But all computers are Von Neumann machines [], and the trick is just to line up the 1s an 0s so the solution appears.
        Academically, perhaps this is an area worth further study. Pragmatically, however, it's the equivalent of saying fat people prefer bigger belts. True, but uninformative, imo. Plus. I never liked Whorf that much anyway. H
    • OOP as a concept is going to have similar constructs, no matter what the language, right?

      The basic concepts, yes. How the platform or language treats things, not necessarily. Here's a specific OOP example between the latest so called "fad" languages. In Java methods are implicitly virtual. In C# you have to explicitly declare a method as virtual. Prescriptive guidance as to how one should go about determining which methods to mark as virtual is only relevant to one of these languages. So while you are cor
  • Here's the blog... (Score:3, Informative)

    by mcho ( 878145 ) on Tuesday June 28, 2005 @06:03PM (#12936276) Homepage Journal
    Click on this link for the blog [].
  • by Anonymous Coward
    Thats what I've found. Another .net language syntax is book is hardly useful. You find yourself wondering what the fuck you would do with all these new wonders and you can think of a 100 better ways you might design code compared to your procedural past but your head is left spinning with options. That is where the design patterns come. OOP ways to do different things which can have a huge impact in the future of your coding. Also MS Press has been doing a bang-up job in documenting the net framework APIs.
    • The usefullness of Patterns is really just a symptom that you're not solving the right problem or using the wrong tools.

      Paul Graham said it best []:

      For example, in the OO world you hear a good deal about "patterns". I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work. When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at

      • That's funny because the Rails people go on and on about how it does MVC and all which is... you guessed it... a design pattern.
        • Yes, it does MVC to the point where you don't have to think about it. It helps to understand MVC conceptually to grok the way Rails does things by convention, but other than that...

          ActiveRecord in Rails is based on...Fowler's ActiveRecord pattern, and it is implemented using SingleTableInheritance pattern for the data persistence side of things, too (but it would be nice if one could get it to do multiple table inheritance as well just as easily).

      • Patterns are just ways to solve known problems.

        Use patterns to solve well researched problems, but never code to a pattern.
      • No, it just goes to show that Paul Graham is a very smart guy with lots of blind spots. A good design pattern does not mean that there's unecessary redundancy in the code; it means that you've applied a proven solution to a known problem (better yet, a proven, matching series of solutions, with known side effects, to a problem). One of those solutions may well be to use Lisp - that solves a certain set of problems, and creates others.

        If you want to really understand design patterns, there's really no way
      • Well, in that case, a "for loop" or "if...then...else" are 'patterns' as well.

        The idea behind good patterns is to reduce common coding occurances into a generic pattern. Sort of a meta code reuse scheme.

        Rather than focusing on rewriting a stack or queue from scratch, you just use something called a stack or queue (more generically, a "list") that functionally does the operations, i.e., push, pop, swap, count associated with what you want to use. You don't care if it's implemented as an array, a linked lis
    • This actually *IS* probably a good book in general for C#. Most of the other C# books really are Visual Studio .Net expositions, and are really not so helpful for using SharpDevelop, the C# plugin for Eclipse, etc.

      It's disappointing that the C# Programmer's Reference, by O'Reilly, still doesn't pay any homage at all to other coding environments. If I wanted a VS.Net reference, I'd buy one. I just want a C# reference, to which it is, for about 3/4 of the book.
  • by jeff67 ( 318942 ) on Tuesday June 28, 2005 @06:08PM (#12936327)
    The review is missing something important. Effective C# is of the same mold as the Scott Meyers' Effective C++ [] franchise - known by many C++ programmers as a great resource of best practices. Bill has Meyer's approval to publish an "Effective" book, and even announced its publication [] on his mailing list.
  • by DJProtoss ( 589443 ) on Tuesday June 28, 2005 @06:12PM (#12936370)
    tbh, I'm not sure that that is a recommendation. We have been going over cc in a reading group at work for the better part of a year now (chapter a week takes a while!), and overall, while he does have a lot of worthwhile stuff to say, the book is mostly dross, coupled with misleading stats, poor editing (and occasionally worse writing) lack of direction and bad analogies.
    On the other hand, it has proved useful as a talking point in our reading group (a mix of professional programmers ranging from fresh grads to seasoned vets). As for the C# book, well we could do with a good reference for the language (although a decent c++ book and a little java and .net knowledge will pretty much provide that anyway)
  • by ufnoise ( 732845 ) on Tuesday June 28, 2005 @06:19PM (#12936430)

    Often Wagner's recommended approach is contrasted against bad practices, or practices which might be optimal in other languages but work poorly in C#. An example of this would be Chapter 4's Item 31: "Prefer Small, Simple Functions," where Wagner shows how smaller functions are generally more efficient than larger functions with complex loops. This probably confounds experienced C++ developers, but it's a prime example of how valuable this book is. Wagner shows that .NET's Just-In-Time compiler pays less cost when calling functions than it does trying to wade through convoluted loop logic. His recommendation? Write "the clearest code you can create. Let the JIT compiler do the rest."

    I don't know how he got the impression that experienced C++ developers would be confounded by short functions. By using short inlined functions, C++ developers don't pay any cost by breaking up large routines.
    • Not only do we avoid paying anything when using inlined functions, but also get really aggressive optimization when using template algorithms. Using std::for_each, std::find_if and friends on containers has become the norm for me, rather than the exception.

      It's funny how they hype the features of new programming languages, while they seem to miss what is already in C++. Personally, i can't really take seriously a language without proper template support.
  • C# is a GREAT language, this is coming from a long history in Oracle/Unix/Linux. I don't understand where people got the idea that it won't work on Linux either. We're coding 3-monitor full screen 3d MRI analysis applications in it, and I can assure you that it has accelerated our developement time over the last iteration created with Borland C++ Builder. Ironically, it took 8 years to write the last version of our software in Builder, and 6 months to completely rewrite it with enhancements in c#. That, consequently, was with both the lead developers having no experience with the language (I was a C++ folk, and he'd been using Delphi, so we settled on C# since it was essentially the next evolution of Delphi).

    It's no joke, and I'll be buying this book just to have it. I've also picked up most of the Deitel series of books on c#, and of course the O'reilly books. The c# cookbook is another GREAT reference. Anyone interested in starting with C# should check for examples. Also, along with a rude admonishment to the MS haters for not having researched the topic (MS dependant indeed), check for a native crossplatform compiler for c#. It's cheap too, but doesn't do forms support just yet (when it does, I'll probably move from VS just to get free cross-platform compatability).


    • So it took 8 years to develop the application from the ground up, and just 6 months to rewrite it for C#.

      Say... If you were to rewrite it in C++, would you have spendt 8 years or closer to 6 months?
    • dude, it makes the platformn MS dependant.

      Sure, you write nice app, that run in Linux, them MS pull the licesing for non windows, and then all the nice linux stuff will only be allow to work on the MS boxes.

      And yes, I have worked in the .net envoronment for about 4 years.
      VS sucks, but that is a different issue. Of course have a project that compile a dll larger then 100K can cause reference issues. the VS and C# camps point at each other for this one. I think it's a c# issue becasue it doesn't happen in V
      • 1)C# is ANSI standard, if MS decides to close THEIR part of the standard off and make it proprietary (read j#) I'd have to make that decision then, but I'm confident that with Novell's backing, mono is going to keep ANSI c# with at least the 1.1 runtime ports working fine for the forseeable future. Out of all this take away, my application works today on 2 platforms, if MS wants to change something in the future, I can choose to go forward with them or choose to stay where I am.

        2) Mono is NOT smoke and mi
      • "Of course have a project that compile a dll larger then 100K can cause reference issues."

        Err WHAT are you talking about?? I to have been doing .Net development for 3-4 years, and I've never heard of this.

        The project I'm working on currently (windows client) has an EXE and 22 DLLS, totalling over 8mb. there are a 3 DLLs over 1mb, and one over 2mb.

        Never seen or heard of the problem you're describing. VS can be a bit flakey at times, but I've got nothing but praise for the .net framework itself. It
    • GNU Mono is also a great place to start if you want a free C#/.NET environment. I'm using it to develop in C# on my Powerbook, and it's been smooth sailing so far. I've been impressed with how quickly some of my apps have come together.

      C# is a nice language. A very refreshing change of pace from C++. .NET is a pretty neat platform, to the extent that it is open and portable. I don't care much for the Windows-specific aspects of it of course.

    • I thought I was going to have to join the "I hate Microsoft but I like C# club", but then I discovered Python. Now I can keep my anti-MS viewpoint.

      Thank you, Guido!!!

  • C# Book (Score:2, Funny)

    by Rac3r5 ( 804639 )
    I personally use Herbert Schildts: "C# a complete reference" for reference.
    It teaches u how to program in the first half and in the second half it has references to all the libraries.

    I find C# pretty straight forward if u know Java.

    I love programming in languages that have their own memory management. Worrying about pointers and what not takes away so much time from productivity. For ppl who wanna get hardcore and want control. Yes u can embed Assembly in ur C# code.

    Now if only someone makes microcontrol
  • I started working on a hardcore C# project around the end of last fall. Effective C# has been my guide and while there are a few recommendations that I'm still experimenting with, I must say I have been very pleased with the results of following its recommendations. While I do concur that the number of typos was surprising, most are simply a missing space between two words and thus little is lost other than the finish of the book. In general, the entire "Effective" series of books has been equally useful, t
  • Simply put, notice the ethics of the post. Good ethics are not often seen.
  • Disclaimer for .NET haters: Mono [] --open source dev tool for .NET. It's nice i've got it on my gentoo partition :-)


    The MS bashing is quite disturbing. Well i know that /. is pretty much a open-source favoring crowd, but MS Visual Studio 2005 is a nice improvement upon the previous edition. The gripes most had about the old version have been fixed, and there are quite a few great improvements, including my favorite improved intellisense! :-)

    While i may have made myself flamebait, i think

From Sharp minds come... pointed heads. -- Bryan Sparrowhawk