Errata

Head First C#

Errata for Head First C#, Fifth Edition

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
PDF Page Page 29 (Blazor Learners Guide)
In Sharpen your Pencil, there is no " MainPage.xaml.cs. ". Visual Studio does not automatically added a method called Button_Clicked

When added the Clicked event handler to your animal button, Visual Studio does not automatically
added a method called Button_Clicked and there is no "MainPage.xaml.cs." exits.

Htu Aung  Jan 06, 2025 
Printed Page CH04 P.236
The last line of handwriting

C# ignores underscores in your number literals, so we used "commas" to make our long numbers easier to read.
should be
C# ignores underscores in your number literals, so weused "underscores" to make our long numbers easier to read.

Joy Chan  Mar 21, 2025 
Printed Page CH05 P.316
The last line of A in the last Q&A at the bottom left half

For example, the SecretAgent class might have a public read-only field with a backing field for the "name":
should be
For example, the SecretAgent class might have a public read-only field with a backing field for the "number":

Joy Chan  Mar 21, 2025 
Printed Page CH06 P.392
Line 6 of the middle box on the right

It also had a CalculateDamage "class" for the subclasses to override,
should be
It also had a CalculateDamage "method" for the subclasses to override,

Joy Chan  Mar 21, 2025 
Printed Page CH06 P.397
Line 17

An abstract method only has a "class" declaration but no method body
should it be
An abstract method only has a "method" declaration but no method body

Joy Chan  Mar 21, 2025 
Printed Page CH07 P.418
Handwritten paragraph 2

Since the Defend method is part of the "IDefend" interface, the NectarDefender class must implement it or it won’t compile.
should it be
Since the Defend method is part of the "IDefender" interface, the NectarDefender class must implement it or it won’t compile.

Joy Chan  Mar 21, 2025 
Printed Page CH07 P.461
"4 Run your app!" paragraph lines 2 and 4

You created an instance of a data object, set the "data context", and added a binding. Now the Label control uses that binding for its Text property. The binding tells it to read its data from the CurrentMood property in the "data context".
should it be
You created an instance of a data object, set the "binding context", and added a binding. Now the Label control uses that binding for its Text property. The binding tells it to read its data from the CurrentMood property in the "binding context".

Joy Chan  Mar 21, 2025 
PDF Page page 617
In the exercise.

Error: Compute a specific power of 2: Math.Pow(power, 2)

I was confused here for a while until I realized it was mistake (I didn't look at the solution). I solved the exercise with the assumption that you meant (2, power).

And after looking at the solution, yeah this must be a mistake.

Aaron Omary  May 14, 2025 
PDF Page Go Fish page 21
Mock random

The mock random was causing an issue with the random player method when running tests. Basically, if you run all tests in a sequence, the mock random would effect the RandomPlayer method and make the test fail:
Message: 
Test method GoFishTests.GameControllerTests.TestNextRound threw exception:
System.InvalidOperationException: Sequence contains no elements

Stack Trace: 
ThrowHelper.ThrowNoElementsException()
Enumerable.First[TSource](IEnumerable1 source)
GameState.RandomPlayer(Player currentPlayer) line 40
GameController.ComputerPlayersPlayNextRound() line 66
GameController.NextRound(Player playerToAsk, Values valueToAskFor) line 52
GameControllerTests.TestNextRound() line 31
RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

The AI explained it to me, idk if it was something I was doing wrong or not, but running the test on it's own it passed, but if I run them all back to back it fails. I think somehow the mock random is like setting the random value from one test but not resetting it on that test. So that's why running it on its own works, but running all tests back to back it breaks.

I was so confused for atleast 3 hours trying to figure this out before I went to the AI, and I'm taking a break now, but hopefully I can move forward next time. Putting this here for you though, cause that was not fun lol.

Also, it may just be something I'm doing wrong, so you probably want to just toss this errata submission! (tackle at your own risk, cause I'm making no sense at this point)

Sequence contains no elements comes from this line in GameState.RandomPlayer:

return Players.Where(p => p != currentPlayer)
.Skip(Player.Random.Next(Players.Count() - 1))
.First(); // <-- throws when the sequence is empty

What makes the sequence empty?

Players.Where(p => p != currentPlayer)
With two players (the human and one computer) this yields one element.

Players.Count() – 1
With those same two players the upper-bound passed to Next is 1.

Real System.Random would only ever return 0 when you call Next(1) (because the upper-bound is exclusive), so .Skip(0) would leave the one element in place and .First() would succeed.

Your MockRandom ignores that upper-bound:

public override int Next(int maxValue) => ValueToReturn; // no range check

In GameStateTests.TestRandomPlayer you set ValueToReturn = 1.
Because Player.Random is static, that instance is still in place when
GameControllerTests.TestNextRound runs.
Now Next(1) returns 1, .Skip(1) removes the only opponent, the sequence is empty, and .First() throws the exception that the test reports.

Aaron  Jun 02, 2025 
PDF Page 12 (Hide and Seek project)
Class Diagram for the GameController

In the class diagram is has "private House house", house is supposed to be static, so this isn't possible right?

I asked chatGPT and it said:
"The diagram shows a field named “private House house” inside GameController. This is incorrect: the House class is declared static, so it cannot be instantiated or stored in a variable. Remove that field from the diagram and any sample code. GameController should refer to the map through House’s static members, for example:

public Location CurrentLocation { get; private set; } = House.Entry;

This eliminates compiler error CS0712 and keeps the diagram consistent with the exercise requirements.

— Errata note provided by ChatGPT"

Aaron O  Jul 07, 2025 
Printed, PDF, ePub Page 26
Screenshot at the Bottom

Hi Andrew.

I bought the fifth edition so you are going to get my errata again.

I have tried for two days to get my screen to look like the picture on page 26, but I cannot get the top line ("Home") to show with a background. It always looks like the screenshot on page 24. I am using .Net 9 and have made sure my code matches yours. I know it is not a huge technical issue, but I wonder why my top line has no background.

Jim Cupec (Thanks for the acknowledgement!)

Jim Cupec  May 22, 2025 
Printed, PDF, ePub Page 44
Last instruction in step 3

The instruction says "Add a ; after the closing curly bracket."
but It should say "Add a ; after the closing bracket."

Also, this is a bit redundant because it shows to do this in step 2 on the previous page.

Jim Cupec  May 23, 2025 
Printed, PDF, ePub Page 44
Example code for step 3

You show a closing comma after the last item in the list. It certainly is not necessary. It may also generate a syntax error.

Jim Cupec  May 23, 2025 
Printed, PDF, ePub Page 45
Code Example

The namespace is missing the opening and closing {}.

Jim Cupec  May 23, 2025 
Printed, PDF, ePub Page 55
Second and third paragraphs

The text states to inserting the code from the "Sharpen" exercise after the opening curly brace of the button event handler. That would reinitialize the variables each time the event is triggered. The first three lines of code should be inserted before the event handler.

Jim Cupec  May 24, 2025 
Printed Page 71
Second paragraph

The text suggests that you should always initialize your variables. I agree. However, in theChapter One Maui exercise, you simply declare the matchesFound variable. I believe you should change the code to
int matchesFound = 0; It is not good practice to let it default.

Jim Cupec  May 24, 2025 
O'Reilly learning platform Page 251
XAML code

The solution only shows 6 <RowDefinition/> statements. However, the last label "guacamole" references Grid.Row="6". That is the seventh row. I added another <RowDefinition/> and the code worked. The code on gihub is also wrong.

Jim Cupec  May 30, 2025 
Printed Page 319
CalculateDamage() method

May have made a mistake but...

Damage = BASE_DAMAGE seems to be superfluous.

Damage is immediately replaced by the next line of code and there are no logic checks to ever retain the default value.

Damage = (int)(Roll * magicMultiplier) + BASE_DAMAGE;

Andrew Perkin  Apr 15, 2026 
PDF Page 443
Sharpen your pencil Solution

I don't understand this line:
bees[6] = bees[0] as Object;

I added it to the project and it won't compile (I also thought that before checking the solution).

I asked chatGPT and it said this:
---------------- (start of gpt comment)
From the snippet,

bees[6] = bees[0] as Object;

is attempting to take whatever is in bees[0] (a HiveDefender in the example) and cast it to object, then store that in bees[6].

However, because bees is declared as an IWorker[], every slot (bees[6] in this case) must hold something that is an IWorker. An object reference does not automatically convert back to IWorker. In other words, you can’t do:

IWorker[] bees = …;
bees[6] = (object)someObject;

without an explicit cast to IWorker.

So, if you literally write bees[6] = bees[0] as Object; in C#, it will not compile, because there’s no implicit conversion from object back to IWorker. (You would see an error like “Cannot implicitly convert type ‘object’ to ‘IWorker’.”)

If your goal was simply to store the exact same HiveDefender object in bees[6], you’d either do:

bees[6] = bees[0];
// or
bees[6] = bees[0] as IWorker;

Both of these store the same reference in bees[6]—no new object is created.
TL;DR

bees[6] = bees[0] as Object; tries to store an object where an IWorker is required.

That won’t compile.

Using as IWorker (or just = bees[0]) would compile and would make bees[6] point to the same underlying object as bees[0].

---------------- (end of gpt comment)

Are we (me and GPT) correct in thinking that this line won't compile, or is there something I'm missing?

Aaron Omary  Mar 24, 2025 
PDF Page 455
in code example

An example of using the protected access modifier has been described, but in the code we only see private and public access modifiers.

Wiktor  Jun 13, 2025 
PDF Page 455
in code example

An example of using the protected access modifier has been described, but in the code we only see private and public access modifiers.

Wiktor  Jun 13, 2025 
PDF Page 512
in code example

Dictionary example:

Dictionary<string, Duck> duckIds = new Dictionary<int, Duck>();

TKey different type:
left: <string, ...>
right: <int, ...>

Wiktor  Jun 23, 2025 
PDF Page 513
in code example

Dictionary example:

Dictionary<string, Duck> duckIds = new Dictionary<int, Duck>();

TKey different type:
left: <string, ...>
right: <int, ...>

Wiktor  Jun 23, 2025 
PDF Page 652
Watch it!

ChatGPT claims it's a mismatch in .net versions, here's gpts explanation (I was confused and still am tbh):
Current wording (paraphrased):
“JsonSerializer only serializes public properties (not fields) and requires a parameter-less constructor. …
If you try to deserialize a SwordDamage object—which has a constructor that takes an int—JsonSerializer will throw an exception.”

Problem:
Just a few paragraphs earlier the chapter successfully serializes and deserializes a Guy object whose only constructor is a parameterised C# 12 primary constructor:

internal class Guy(string? name, Outfit clothes, HairStyle hair) { … }

Running that code on .NET 8 (SDK 8.0.x) works without custom converters or [JsonConstructor] attributes, contradicting the statement that a parameter-less constructor is required.

Why this happens:
System.Text.Json behaviour has changed since .NET Core 3.1, when the chapter was likely drafted:
.NET version Deserialization rule (simplified)
3.0 / 3.1 Must have a public parameter-less constructor.
5.0 / 6.0 Parameterised ctor allowed if it’s marked [JsonConstructor] (or if it’s the only public ctor, per docs).
7.0 / 8.0 If a class has one public ctor whose parameter names match the JSON, it’s used automatically; primary-constructor classes and positional records work out of the box. No default ctor needed.

So the book’s warning is accurate for .NET Core 3.x but outdated for current LTS releases.

Suggested correction / clarification:

“Earlier versions of System.Text.Json (up to .NET Core 3.1) required a public parameterless constructor for deserialization.
Starting with .NET 5, a public parameterised constructor will also be used if either

it’s the only public constructor, or

it’s marked with [JsonConstructor].

Therefore the Guy example works on .NET 7/8 because it has exactly one public primary constructor whose parameter names match the JSON.”

A footnote or sidebar noting the version-dependent behaviour would prevent confusion for readers using newer SDKs.

How the confusion was found:
I double-checked the chapter code in a .NET 8 console project and consulted AI (ChatGPT) plus current Microsoft docs. Both confirm that parameterised constructors are now supported.

If this isn’t actually an error but intentional version targeting, please clarify the intended framework version at the start of the chapter.

Aaron  Jun 12, 2025