Programming C# by Jesse Liberty 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. This page was updated May 13, 2003. 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 UNCONFIRMED errors and comments from readers: (6) paragraph 6, name of the second author should be read as Hoang instead of Hoag. (14) Example 2-3; Example defines class Hello. text that follows describes class HelloWorld instead. [16] The static Keyword: 1st sentence after the code ; Not sure if the static keyword means there is no creation of an object of type Hello class or type HelloWorld class. (Please refer to the Hello World example on page 9, 11, 14, and 15. You say HelloWorld class the first time, but Hello class the other times.) {25} table 3-1; char is listed as taking up one byte. Char's in C# are, as listed, Unicode characters and thus must take up 2 bytes. Visual Studio.Net documentation confirms this. {25} table; The table says that char has a size of 1 byte. In fact the C# language specification in section 4.1.4 says that it has a length of 16 bits (2 bytes). {26} end of 2nd para; "...while a ulong can hold values from 0 through 4,294,967,295." Maximum value should be 18,446,744,073,709,551,615? [26] table of built-in value types; The maximum value for a ulong is given in hexadecimal, with 0x notation, which isn't introduded yet in the text. All other values (even those for long which is +/-9 quintillion) are given in decimal. Surely the maxiumum value for a ulong should also be given as a decimal (18,446,744,073,709,551,616) or as ~18.5 quintillion. {26} table of build-in value types; The minimum value for an int is given as -2,147,483,647; it should be -2,147,483,648 (one less) as it is a 32-bit twos complement number. (Note that all signed types are twos complement and so their lower bound is even). [27] Box: the stack and the heap; Stack is described, but heap is not [33] bottom of page 33/top of page 34; The examples in the the discussion of enumerations starting on page 32 do not work as written with CS .NET Enterprise Beta 2. As far as I can tell, an explicit cast, for example, System.Console.WriteLine{"Freezing point of water: {0}", (int)Temperatures.FreezingPoint ); is needed. Without the cast, the text of the label of the enumeration element rather than its value is displayed. In the docs I found "The underlying type specifies how much storage is allocated for each enumerator. However, an explicit cast is needed to convert from enum type to an integral type." (38) 2nd paragraph; 2nd line reads: [...] continue, return, or statementhrow Assuming it should have been just "throw" {42} 3rd paragraph; The sentence: "Because any nonzero value evaluates to true in C and C#" should read: "Because any nonzero value evaluates to true in C and C++". (45) Example 3-10; The indentation in many of the examples is quite poor, but this one is particularily bad. The following part was confusing: if (i < 10) goto repeat; return 0; [47] top of page; "do expression while statement" should be stated "do statement while expression". [49] Text box, last code snippet; The code will not compile as too many braces have been shaved off. The variable "i" is not available for the "if" statement. (49) box on Whitespace and Braces; oOn page 49 in the section on Whitespace and Braces the last example will not work since without the braces for the for statement the if statement is no longer part of the for statement and i is therefore out of scope. And even if it was the if statement would only be executed once after all the iterations through the loop. [49] 3rd example in Whitespaces and Braces box; The example removes both sets of braces and indicates that the program would remain unchanged, when this is not the case. The original program includes two statments inside the first if statment: the Console.Write and 2nd if statement. The revised version includes only the Console.Write statement. The 2nd iff statement would only be evaluated once, after exiting the first if statement. [49] the last code snippet is written as: for (int i = 0 ; i < 100 ; i++) Console.Write("{0} ", i); if (i % 10 == 0) Console.WriteLine("\t{0}", i); while it needs to be written as: for (int i = 0 ; i < 100 ; i++) { Console.Write("{0} ", i); if (i % 10 == 0) Console.WriteLine("\t{0}", i); } You took out one set of braces too many. (56) table; In the second line, in the third column the operator should be == instead of = {65} First sentence; Should read "#endregion", not "#end region" (77) at the bottom there is the following code public void SomeMethod (int hour) { this.hour =3D hour; } Previously the book is using a running example of a class 'Time' that = has a member field of 'Hour' (capitialized). On page 78, in discussing the code above, the text reverts to the Pascal = Hour. [81] 3rd Paragraph; The last sentence says that without a public constructor it will not be possible to create an instance of the class. This is not true. It is possible to have only a private constructor and a public static method that calls the constructor. Some consider this approach to be better that having a public constructor as it means that all the public methods can be in an interface resulting in better decoupling between types & implementation. (97) Top of the page; Figure 5-2 and Figure 5-3 are indentical, but figure 5-3 is supposed to show an expanded UML representation of windows widgets... {113} there is the definition for an abstract calss called Window. Within the Window class, two variables are defined called top and left. The comment that appears above them reads; // these members are private and thus invisible // to derived class methods. We'll examine this // later in the chapter. Then the two variables are declared immediately after, thus; protected int top; protected int left; The access modifier provided in the declaration is protected, not private so the two variables are not invisible to derived class methods. [116] last line; the method string ToString() in the last line is described as virtual. as far as i understood it should be override NOT virtual. in later examples the override is used also. {120} tip: Java programmers take note; static and non-static switched nested classes are roughly equivalent to inner classes (non-static); there is no C# equivalent to Java's static nested classes. also: inner class is Java's term for non-static nested classes. static nested classes are just called static nested classes. static inner class is a contradiction. {121} Last line on page; "FractionArtist is public". It appears to be defined in the example as "internal". [Yes, it can be accessed from outside Fraction -- in that sense it is "public" -- but it's not REALLY "public" Also, that sentence seems to be worded badly: "it is scoped to within the Fraction class"?!?! {124} 4th Paragraph, under the discussion on "The Equals Operator"; Last sentence of this paragraph states "Thus, for example, ArrayList expects you to implement Equals().", where the author must hav e meant: "Thus, for example, Fraction expects you to implement Equals().", since the "ArrayList" word in the previous sentence is not consistent with the ongoing discussion prior to this topic, where the au thor was using a "Fraction" class as an example. (128) code under 1st paragraph; "return new Fraction(theInt,1)" should read "return new Fraction(theInt)" for it is referring to the conversion operator in example 6-1, and is calling to the constructor that only takes an integer as an argument, as it is stated on the paragraph after the code. [143] Last sentence; "Running this modified example..." Is the example missing? [159] under "static void Main()" half way down the page; Document theNote = new note("Test Note"); should be: Document theNote = new Document ("Test NOTE"); (175) "Owl" tip; Should read Button[] myButtonArray = new Button[3] {177} Example 9-2 line empArray[i]=new Employee(i+10) should read empArray[i]=new Employee(i+5) as in example 9-1 if the output is to agree, (187) last line of code; comment in Example 9-7 reads: // initialize each Employee's vaue should be: // initialize each Employee's value [214] Missing method in program 9-14; When I entered this program, I get a compiler error "No overload for method 'Add' takes two integers" (227) Code Sample Console.WriteLine("myHashTable["000145938"]: {0}",hashTable[ "000145938"]);; The quotation marks with the string index for myHashTable within the Console.Wr iteLine string needs to be escaped. In other words the code should read: Console.WriteLine("myHashTable[\"000145938\"]:{0}",hashTable["000145938"]); (231) 1st section of source code on page; Iconvertible should be IConvertible in the declaration given for class String [237] 1st paragraph; The first paragraph says: In this case the output properly indicates that s1 is "less than" s2. In Unicode (as in ASCII), a lowercase letter has a smaller value than an uppercase letter. How can "a" which is decimal value 97 in the ASCII table be smaller than "A" whose decimal value is 65?? [288] 2nd Code first Line; studentPair.Sort(theStudentDelegate); Build error Should be studentPair.Sort(Student.OrderStudents); No Build Error [291] 3rd code block; Surely the lines: public DoEffect BlurEffect = new DoEffect(Blur) public DoEffect SharpenEffect = new DoEffect(Sharpen) public DoEffect FilterEffect = new DoEffect(Filter) public DoEffect RotateEffect = new DoEffect(Rotate) should read: public static DoEffect BlurEffect = new Blur() public static DoEffect SharpenEffect = new Sharpen() public static DoEffect FilterEffect = new Filter() public static DoEffect RotateEffect = new Rotate() I have not tested this yet, but there is nothing in the text to explain how the DoEffect delegate can be constructed with a function as a parameter. {294} 5rd paragraph; I think the SetCheck() method has some minor problem. In your book, you write these private void SetCheck(TreeNode node, bool check) { node.Checked = check; foreach (TreeNode n in node.Nodes) { if (node.Nodes.Count == 0) { node.Checked = check; } else { SetCheck(n,check); } } } It can not run correctly. I have seen the last update source code for downloading in your website. In the source code, the SetCheck has changed to private void SetCheck(TreeNode node, bool check) { // find all the child nodes from this node foreach (TreeNode n in node.Nodes) { n.Checked = check; // check the node // if this is a node in the tree, recurse if (n.Nodes.Count != 0) { SetCheck(n,check); } } } Though it can work correctly. But I think the if statement (judge if n.Nodes.Count!=0 and SetCheck) is unnecessary. Because when n.Checked=check is execute, it will activate the AfterCheck event again, then we have already a recursive. Do not need a if stament and SetCheck to form another recursive. I have removed if(n.Nodes.Count !=0) statement, and the result is fairly well. Please consider my opinion. (315) third code example; The example says: one:btnCancel.Click += new System.EventHandler (this:btnCancel_Click); The text "one:" should be deleted. [331] Second half of page; The implementation of tvwSource_AfterCheck calls SetCheck, which sets the Checked attribute of the calling node to the passed in value. This triggers the AfterCheck delegate and results in an infinite recursion. This is with the version 3705 of the .net framework. To fix it, change tvwSource_AfterCheck code to the following and remove the SetCheck function. The n.Checked line below triggers the AfterCheck delegate and gives the desired recursion. protected void tvwSource_AfterCheck( object sender, System.Windows.Forms.TreeViewEventArgs e) { foreach (TreeNode n in e.Node.Nodes) { n.Checked = e.Node.Checked; } } [335] Last code sample; The line FileInfo file = new File(fileName); should read FileInfo file = new FileInfo(fileName); {368} Example 14-1; The book breaks the coding standards that are specified within the book (page 15) in many places (mainly with regards to capitalization of variable names), but this listing is particularly bad: DataSet DataSet = new DataSet(); Here an object is given the same name as the class. In the same code listing there is also: SqlDataAdapter DataAdapter = ... {405} Figure 15-2; Web Application icon should have a name as "ASP.NET Web Application". (405) 1st paragraph; Original: The solution files and other ... in \Documents and Settings\\MyDocuments\Visual Studio Projects... Should be: The solution files and other ... in \Documents and Settings\\My Documents\Visual Studio Projects... 1) Remove the word before Settings. 2) The word "and" should be italiced since it is part of a pathname. (Please refer to the Conventions mentioned in page xvi.) 3) "MyDocuments" should be "My Documents". There is no folder with name "MyDocuments". (405) 3rd line of last paragraph; "View Code in the pop-up menu." should be: "View Code" in the pop-up menu. (405) 2 line of last paragraph; WebForm1.cs should be WebForm1.aspx.cs (406) last line of 2nd paragraph; HelloWeb.cs should be HelloWeb.aspx.cs {406} Example 15-2; 2nd line should be: Codebehind="HelloWeb.aspx.cs" After the beginning <% %>, there should be a line start with After the line, there should be 2 more line with meta content. {406} code fragment after Example 15-1; Again the Codebehind="HelloWeb.cs" should be Codebehind="HelloWeb.aspx.cs" (406) last paragraph; HelloWeb.cs should be changed to HelloWeb.aspx.cs (407) Figure 15-2; The figure displays the wrong output. It displays the form developed in chapter 13 (shown in Figure 13-1). It should be displaying a screenshot of IE showing a white page with the message "Hello world! It is now" followed by the current date & time. {407} 2nd code listing; - Pow(a, 0) should return 1, but it returns a! This implementation says a^0 = a^1 which is not true for all the a's. - The method doesn't handle exponents correct if they are not ints 8.666^4.74 should be treated as (8.666 ^(474/100)) not (8.666^4) - Also negative exponents are not handled with this method. 8.666^(-4) is (1/(8^4)) [411&412] bottom 1/4 of 411 top 1/42of 412; Space between System.Data. & SqlClient (twice). Should be System.Data.SqlClient (411 only) SQLConnection used instead of SqlConnection (both pages). e.g System.Data.SqlClient.SQLConnection should read System.Data.SqlClient.SqlConnection also System.Data.SQL.SQLCommand should be System.Data.SqlClient.SqlCommand (in code examples on both pages 411 and 412) [412] Text after 2nd code example refers to SQLDataSetCommand and assigns SQLCommand (which should be SqlCommand) to it. Example code after this relates to myCommand, a SqlCommand object not a SQLDataSetCommand (which I'm pretty sure doesn't exist). {424} pow method; Despite the fact that the pow method takes two double arguments, it will return an incorrect result if the power is negative or non-integer. Maybe it would be better for the method to use System.Math.Pow instead of attempting to calculate the result. Furthermore the name of the function is in lowercase which is not consistent with the other web methods in the example (Add, Sub etc), or the C# coding standards. [465] last sentence; At the bottom of the page it says that typeof returns an object of type Type which derives from MemberInfo. On the next page in the "owl" section it says that MemberInfo derives from Type. which is it??? also, the statement: System.Reflection.MemberInfo inf = typeof(MyMath) is confusioning because the return from typeof(MyMath) didn't require a cast. If typeof returns Type and MemberInfo derives from type then how can this statement work. I'm sure it's correct, it's just that i don't understand it. {527} Example 20-1 code; I haven't run this program yet, example 20-1, but it seems fairly clear that threads one and two will be started, then, while they are running, DoTest will return, and then Main will return, and the program will end because the main thread has ended. wjithout threads one and two being able to complete their work. Also, I don't see any reason for these threads to be run outside of Main, and why there needs to be an instance created of the Tester class. (529) 3rd paragraph from bottom; The text states that a millisecond is 1000 nanoseconds, which is wrong : 1 sec = 1 000 milliseconds = 1 000 000 microseconds = 1 000 000 000 nanoseconds (564) Code sample near the middle of the page; "FileInfotheSourceFile" should read "FileInfo theSourceFile" (579) Example 21-10; Variable declarations should be located at the TOP of a class, not the bottom. Especially when you have a class that starts on one page and ends on another. I was left scratching my head wondering where these magical undeclared variables came from... until I turned the page. {590} middle of code sample; I suggest rewritting this section of code: int bytesRead = reader.Read(buffer,0,BufferSize); if (bytesRead == 0) // none? quite fQuit = true; else // got some? { // display it as a string string theString = new String(buffer); Console.WriteLine(theString); } Like so: int bytesRead = reader.Read(buffer, 0, BufferSize); if (bytesRead < BufferSize) // didn't fill buffer? quit fQuit = true; if (bytesRead > 0) // got some? { // display it as a string string theString = new String(buffer); Console.WriteLine(theString); } Two points: - When I run it as is, the client never finishes, because I never get a zero length buffer. I get one buffer of length 86. This may be because the file I used is smaller than one buffer in size. - In the comment "quite" should be "quit" (594) "Using a Formatter", paragraph 2; "Formatter classes implement the interface Iformatter" The F in Iformatter should be capitalised (should be "IFormatter") - this is the name of an interface, so is case sensitive.