Notes and Errata for C# 3.0 in a Nutshell by Joseph Albahari and Ben Albahari

Here are my comments and errata for this book. Some of the comments I do not believe should be in the book as it would probably make it more difficult to read (like the comments on p. 140):

Safari

Note: The on-line Safari version of this book has no page numbers, which makes reading or using errata like this very difficult. I have organized these errata into chapters to alleviate this problem.

Prologue

p. iv /Nested should be Nested

Chapter 2

p. 17 The statement "Reference types comprise all class, array, delegate, and interface types." may or may not be correct depending on how you interpret a type. A struct that implicitly supports an interface will still be of that interface type and be a value type. If it is cast to the interface type, then it will be boxed and hence a reference type. Explicit interfaces require a cast.

p. 20 (top of page) "at minimum the overhead is 12 bytes". I believe this disagrees with the CLR via C# book which requires 2 32-bit entries (8 bytes) and the flag is folded into the lock. I need to look this up. The confusion here may be the "extra" 4 or eight bytes for the indirection. The paragraph is worded vaguely.

Table 2-1 For real numbers, the +/- applies to the entire range, not just the small magnitude values.

Table 2-5 Similar to Table 2-1 but the +/- is missing.

p. 44 (code example) This is not obvious (and perhaps not correct) without a thorough understanding of integer arithemitic and 2's complement representation (which is what I assume the CLR requires - old Cray programmer here). In any case, not the best example for this book to make the point.

Chapter 3

p. 60 (chapter 3) private can also precede the keyword class.

p. 61 The field modifiers have an inconsistent case - they should all be lower case.

p. 65 (Note at bottom) Personal peeve - Good programming is never a distraction! All authors should use properties and favor the "as" keyword over casting.

p. 67 (Automatic properties) There shoud probably be more on this. It may not be obvious at first glance, but both a get and a set are required unlike normal properties. Note sure if you can add a body to either (you can not). I assume the get could also be marked private (it can, I just ran a test).

p. 70 (Access modifiers) Again the case should be lower case.

p. 71 (Finalizers) May want to make a comment here that these can not be called directly.

p. 74-75 (Casting) Note: "Casting" and "Conversion" use the exact same syntax. This section strictly discusses "casting" - the process or re-labeling an object to belong to a different category or type. To avoid confusion, an object should never be "cast" to another object using the conversion syntax (e.g., IList list = (IList)myArray). The "as" opertor should always be used to avoid this confusion (e.g., IList list = myArray as IList).

p. 88 (Explicit Interface Implementations) Explicit interface implementations should never ever be used to resolve collisions between interfaces as shown in the book. If you have this, throw your code away and re-write it!

p.99 data[position] should be data[index]

Chapter 4

p. 119 Func <T> should be Func <TResult>
p. 119 Func <T,TResult> (T1 arg) should be Func <T,TResult> (T arg)
p. 119 Action <T,TResult> (T1 arg) should be Action <T,TResult> (T arg)

p. 120 (last paragraph). The outer variable (seed) can change between invocations (unless seed is copied since it is a value type). Not sure.

p. 130 (Enumeration - first sentence) read-only applies only to the collection, not the elements in the collection.
p. 130 (Enumeration - first sentence) forward-only is perhaps incorrect. We may want it to be 1) deterministic, 2) make progress 3) visit an element at most once and possibly 4) visit each element. None of which is required or even generally accepted (yield break). This is just the behavior exhibited by arrays and the concrete collection classes. Unless you are saying that implementing IEnumerable<T> and GetEnumerator does not constitute an "Enumerator".

p. 131 From the statement "var enumerator = "beer".GetEnumerator();" it is not clear whether we are using generics or not in this example. Is WriteLine(element) calling WriteLine(object) or Writeline(char)? The answer is that it is using neither!! Both the non-generic and generic GetEnumerator is implemented explicitly for the string class. This actually gets a special CharEnumerator instance.

p. 137 (first code example) The "^" should be a "&" and teh comment should read that a is false as per the statement "a nonnull value is not equal to a null value".

p. 140 The concept that && and || are implicitly overridden by & and | is pretty deep. Makes sense for a set of bool's A&B^C but requires and explanation for say unsigned shorts or better still signed shorts.

p. 140 (last statement) Being an old C++ programmer I have to ask and I believe the answer is that the following statement is okay: Note CSharp = 2 + B; Similarly, using extension methods is it possible to have: int x = B + 2;? Not that I am advocating that we want this or should use it.

p. 142 (Note) Even if the types are strongly related, conversion operators like this one should not be used if it is not obvious what the context is. Here it is not obvious in the usage that 554.37 is a frequency. A FromFrequency method also makes that explicit.

p. 145 I would add a note that the use of Extension methods on Interfaces is perhaps the real reason you want to use them.

p. 147 SerializableAttribute should be ObsoleteAttribute

p. 148 (Unsafe Code and Pointers) I should be pointed out the most common method to include non-C# libraries for interoperabilty is to use Managed C++ to write a wrapper around the existing unmanaged code. Although the comment about unsafe C# not leaving the managed execution environment is a good one. (on p. 149)

Chapter 6

p. 204 (Table 6-5) The example was using a time of 17:18:19, not 17:11:30.

p. 209 (3rd line) the | or cursor before "Beige" should not be there.

p. 211 (Enums) This should be in the Chapter on Reflection.

p. 215 (Referential - last sentence) Does a struct that contains a string do a string comparison or a pointer (reference) comparison? What if the type overrode the equality operator?

p. 215 (Standard Equality Protocols) There are actually five protocols if you add the static Object.Equals and Object.ReferenceEquals methods.

p. 217 (second AreEqual implementation) Note a Customer c=null is equal to an Animal a=null with this implementation.

p. 221 Equality is commutative and associative. This should probably be: "Equality is commutative and transitive". The transitive nature is not included.

Chapter 7

p. 230 "forward-only" Similar comment to p. 130.

p. 257 (Table 7-2) The memory overhead for SortedList has got be greater than 2 bytes. Seems out of line.

p. 265 GetItemForKey is used twice. It should be GetKeyForItem.

p. 268 (top code fragment) It should be pointed out that an explicit cast is not required: IList names = t.Names; names.Add(); should also yield a run-time error.

Chapter 9

p. 320 DemoDataContext does not have a parameterless constructor as used.


Prof. Roger Crawfis
Computer Science & Engineering
The Ohio State University
http:\\web.cse.ohio-state.edu\~crawfis