C# 3.0 in a Nutshell, Third Edition by Joseph Albahari, Ben Albahari The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification This page was updated May 13, 2008. UNCONFIRMED errors and comments from readers: {1} n/a; book is missing any definition or explanation of "friend assemblies" (although they are referenced on p.85 in the definition of the "internal" modifier). I think this is a significant omission. (1) 3rd paragraph; the phrase in line 5: "primitive types such as integrals," should be "primitive types such as integers," (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. (21) Table 2-1 For real numbers, the +/- applies to the entire range, not just the small magnitude values. (26) 5; "Diving zero by zero...results in a NaN." should be Dividing {29} 1st paragraph (continued from previous page); "...if it is not windy" should be changed to "...if it's windy" (54) "Fully Qualified Names" section; You can refer to a type with is [its] fully qualified name... (58) Example code after "Application:" and further; Missing open brace "{" after "class Test" (two times). (60) mid-page; private can also precede the keyword class. {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). (97) 3.9.1. Generic types; I don't know the page number because I'm reading from Safari. The first example of Generics has an error in the definition of Pop method. public class Stack { int position; T[] data = new T[100]; public void Push (T obj) { data[position++] = obj; } public TPop ( ) { return data[--position]; } } should be changed to public class Stack { int position; T[] data = new T[100]; public void Push (T obj) { data[position++] = obj; } public T Pop ( ) { return data[--position]; } } {99} 3rd paragraph; 1st line says Methods can introduce generic parameters. 2nd line also lists methods in the list of constructs that cannot declare generic parameters. I think 'methods' should be left out of the 2nd sentence. {99} Under "Generic Methods" in Swap method; T temp = b; should be changed to T temp = a; (112) the second to last line on the page (highlighted in bold); IMHO this line should be: public event PriceChangedHandler PriceChanged; instead of: public event PriceChanged PriceChanged; {119} 2/3 way down page, in the first line of the code listing; 119) 2/3 way down page, in the first line of the code listing: IMHO, this line: delegate TResult Func (); should be replaced with delegate TResult Func (); (130) Enumeration - first sentence; read-only applies only to the collection, not the elements in the collection. 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 and GetEnumerator does not constitute an "Enumerator". {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. {137} code snippet for Equality operators (== !=); The code snippet for section 'Equality operators (== !=)' on page 137 is as below: bool a = x == y; // translation: bool a = (x != null && y != null) ? (x.Value == y.Value) : (x != null ^ y != null); // a is true If we check the previous page, we will know that x = 5 and y = null. Surely a should be false. If you test the above two assignment, you will find out that the first one returns false, but the second returns true. I think the equivalent of 'x == y' should be (x == null && y == null) || (x != null && y != null && x.Value == y.Value) or (x != null && y != null) ? (x.Value == y.Value) : (x == null && y == null) (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. {147} 11th line from bottom; Namespace="http://blah" in sample code should be http://oreilly.com to be in sync with the text 2 lines up. {151} 8th line; Rather than pointing to a specific value type, a pointer may make no assumptions about the type ... should be: Rather than pointing to a specific value type, a void pointer ... [163] int maxRemainderAfterDivBy5 example; Instead of "numbers.Max (n % 5);" I believe you need a lambda function "numbers.Max (n => n % 5);" (213) second to the last sentence (of title Enumerating Enum Values); The sentence: "Composite members such as LeftRight = Left | Right are included too." after the last code snippet of page 213 (regarding Enum) foreach (Enum value in Enum.GetValues (typeof (BorderSides))) Console.WriteLine (value); When I typed in the example, no composite member was displayed. Only Left, Right, Top, Bottom are shown. ?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? {215} Standard Equality Protocols; There are actually five protocols if you add the static Object.Equals and Object.ReferenceEquals methods. (221) Equality is commutative and associative. This should probably be: "Equality is commutative and transitive". The transitive nature is not included. (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. {314} 1st block of sample code; cust.Purchases.Remove (p2); should be cust.Purchases.Add (p2); {320} mid-way; You use new DemoDataContext with a default constructor, but the code does not contain a default constructor. {433} The "Stream architecture" top of the page figure; In the "Decorator Streams" area of the figure, the last listed stream should be "BufferedStream" and not "BufferStream". {505} 5th bullet point; Actual Text: - Any "known" type decorated with DataMember Correct Text: - Any "known" type decorated with DataContract (i.e. replace "DataMember" with "DataContract") (565) 2nd code listing; the output shown for Consolw.WriteLine(typeof(Dictionary).FullName is actually for Dictionary (not ). {597} Last paragraph; Given ยง10.3.9.1 in the C# language specification v3, I'd say the sentence "By convention, their names are prefixed with 'get_' or 'set_'" is too vague, it's not convention but is so specified. (775) Thru-out whole section; While most contextual keywords are defined in this appendix the following are not: add, join, remove, select, var and where.