C# in Depth

Cover of C# in Depth
Order now (3rd edition)

Table of Contents (3rd edition)

Here's a more detailed table of contents for the third edition of C# in Depth than the "about" page can reasonably be expected to provide. This should tell you everything you need to know about what's in the book, and what's not. If you still have any questions though, feel free to mail me and ask.

Part one

This is an introduction to the book - experienced developers could skip it completely if they really wanted to. On the other hand, it gives an idea of what's coming up, as well as some hints and tips as to how to get the most out of the book.

Chapter 1: The changing face of C# development

This is mostly a roadmap for the rest of the book - a quick demonstration of some of the features in C# 2, 3 and 4. Additionally I explain how I differentiate between C# the language, the CLR as the virtual machine, and the various libraries that make up .NET. Finally there are a couple of bits of housekeeping - a recommendation to download the C# language specification and a warning about using teaching-aid code in production.

Chapter 2: Core foundations: bounding on C# 1

Although C# in Depth is devoted to explaining the features introduced in C# 2, 3 and 4, these only make any kind of sense if you already understand C# 1. This chapter looks at three topics from the first version which are often misunderstood by newcomers to C#, and which are crucial for later versions. We also have a look at how these areas have evolved over time.

Part two

This part of the book covers everything introduced in C# 2, and one new feature from C# 3 (partial methods). By now the topics covered here are reasonably well known, but there are probably surprises for all but the hardiest of C# developers.

Chapter 3: Parameterized typing with generics

As the most important feature in C# 2, generics stand out as a feature which would have been even more wonderful had it been available right from the start. Much of C# as a language and .NET as a platform might be somewhat more elegant if they hadn't had to work pre-generics. Many of the later language features would be pretty much impossible without generics, and it's frankly hard to remember the language without them.

Chapter 4: Saying nothing with nullable types

Love 'em or hate 'em, null values are a fact of life in C#. But until C# 2, we could only use them for reference types. What does it mean for a byte variable to have a value of null, anyway? Isn't null a reference? Well, not any more - at least, not always. .NET 2 introduced the Nullable<T> value type - a wrapper which allows a special value of "there's no real value here" - just like a null reference, in essence. In this chapter we delve into all the details.

Chapter 5: Fast-tracked delegates

Ask a C# 1 programmer what delegates are used for, and they'd probably tell you they're pretty much all about UI events. Maybe occasionally starting a thread, or an asynchronous callback. As time has gone on, delegates have become more and more important in C#. They're a natural way of representing little bits of behaviour, such as the filter or projection to apply in LINQ. In C# 1 they were somewhat awkward to use at times: the behaviour had to be encapsulated in a method, and if that method needed any information other than what was exposed in the parameters, it had to be present in the object the method was called on.

C# 2 fixed a lot of this with anonymous methods, and C# 3 slimmed them down even further with lambda expressions. This chapter is primarily about anonymous methods and their subtleties, although there are a few other delegate-related features in C# 2 as well.

Chapter 6: Implementing iterators the easy way

Sequences are really useful. So useful in fact, they're the underlying data model of LINQ to Objects. It's easy to use them - C# has always had the foreach statement. But what about creating them in the first place? It's fine if you've already got a list or an array, but how about modelling the Fibonacci sequence, or lines read from a text file? That used to be somewhat tricky... but not any more.

Chapter 7: Concluding C# 2: the final features

This is the first "grab-bag" chapter of features... essentially the ones that aren't big enough to deserve a chapter to themselves. Some are only useful in emergencies - others are very handy for everyday use.

Part three

Even C# 3 feels somewhat "old" to me now (as I write this in 2010). However, it's where C# starts to really feel like a modern language - one which lets me express myself with a lot less ceremony than before. With LINQ at its heart, C# 3 makes working with collections of data a breeze - but there's more to it than that.

Chapter 8: Cutting fluff with a smart compiler

Another variety chapter, this introduces several new features. Most of these contribute to LINQ in some way or other, and while they are certainly distinct they feel more closely related than the features we examined in chapter 7.

Chapter 9: Lambda expressions and expression trees

Lambda expressions are like anonymous methods taken a step further: they allow you to create delegate instances more concisely than ever before. They also allow you to create expression trees - a representation of code as data. This is the secret sauce that allows LINQ to SQL and its friends to examine your queries written in C# and translate them into SQL. We examine both in this chapter. Oh, and type inference too. It's painful, but it has to be done.

Chapter 10: Extension methods

Extension methods are static methods in static classes which are made to look like instance methods on completely different types. Is that clear enough? Well, maybe not. It sounds mad, but it's a really useful idea... especially when it comes to interfaces.

Chapter 11: Query expressions and LINQ to Objects

This is the big payoff for everything in part three so far... we're finally at LINQ. In fact, by now there's only one missing piece - query expressions. These somewhat SQL-looking pieces of code are cunningly translated by the C# compiler into perfectly normal bits of C# - which are then compiled using the normal rules. The result is a small but powerful query language. This chapter goes into the details of how query expressions are translated by the compiler, as well as showing what the various parts do in LINQ to Objects.

Chapter 12: LINQ beyond collections

By this point we've seen everything in the language itself, but we haven't really got a good feel for LINQ. How flexible is it? Why isn't it specified in terms of normal interfaces? What are expression trees really there for? This chapter looks at several LINQ APIs very briefly - just enough to show you the breadth of what LINQ can achieve. We also look at how you can write your own extension methods on IEnumerable<T> to extend LINQ to Objects.

Part four

Compared with previous versions, C# 4 only contains a relatively small number of changes. One of them, however, is huge - dynamic typing helps C# interoperate with other languages and platforms.

Chapter 13: Minor changes to simplify code

As you might have guessed from the title, this is another chapter of small-ish features. However, don't underestimate them: I suspect that personally I'll use some of these features rather more than the behemoth of dynamic typing.

Chapter 14: Dynamic binding in a static language

C# has always been static before. The compiler would only allow you to call methods which it knew would be there. If you had more information than the compiler about the actual type of an object, you had to cast the reference or something similar... then it would let you use that type.

All of that changes in C# 4, but in a controlled way. I'm confident that most C# 4 developers will use dynamic typing rarely if at all. However, if you want to work with COM or a dynamically typed language such as IronRuby or IronPython, C# 4 makes it a smooth ride.

Part five

C# 5 has very few features: three really, and only one of those is particularly significant. However, it really is a game-changer.

Chapter 15: Asynchrony with async/await

By far the biggest new feature in C# 5 is language support for asynchrony. C# 5 allows you to declare asynchronous methods (and anonymous functions) which contain await expressions which wait for asynchronous operations to complete... but the waiting is performed asynchronously. It's hard to describe in a single paragraph, but it's what the world's been waiting for when it comes to async code.

Chapter 16: C# 5 bonus features and closing thoughts

The final chapter wraps up C# 5 by covering the two smaller features, and then considers the future briefly.


C# in Depth is a language-focused book, but of course C# is almost always used in the context of .NET. The appendices form a sort of quick reference for three aspects of .NET: LINQ, generic collections, and the various versions of .NET available.

Appendix A: LINQ standard query operators

Although different providers will make different query operators available, the idea is that they should work mostly the same in terms of results. This appendix looks at all the standard query operators and how they work in LINQ to Objects in particular, including optimizations taken.

Appendix B: Generic collections in .NET

Can't remember the difference between a SortedList<TKey, TValue> and SortedDictionary<TKey, TValue>? Not sure whether to use an IList<T> or an ICollection<T>? If so, this appendix is for you.

Appendix C: Version summaries

The versions involved in .NET are confusing - particularly as .NET 3.0 doesn't contain C# 3, for example. Introduce Silverlight, the Compact Framework and other editions into the mix, and it's all a bit tricky. Hopefully this appendix will make things clearer...