Add item for page 235

This commit is contained in:
Mark J Price 2023-04-14 12:12:32 +01:00
parent 627003b8ba
commit de9165c9e6
6 changed files with 218 additions and 32 deletions

View file

@ -4,7 +4,7 @@ If you find any mistakes in the seventh edition, *C# 11 and .NET 7 - Modern Cros
[**Errata** (42 items)](errata.md): Typos, tool user interface changes, or mistakes in code that would cause a compilation error that prevents a successful build. [**Errata** (42 items)](errata.md): Typos, tool user interface changes, or mistakes in code that would cause a compilation error that prevents a successful build.
[**Improvements** (29 items)](improvements.md): Changes to text or code that would improve the content. These are optional. [**Improvements** (30 items)](improvements.md): Changes to text or code that would improve the content. These are optional.
[**Common Errors** (3 items)](common-errors.md): These are some of the most common errors that a reader might encounter when trying to get code in book tasks to work, or when trying to write your own code. [**Common Errors** (3 items)](common-errors.md): These are some of the most common errors that a reader might encounter when trying to get code in book tasks to work, or when trying to write your own code.

View file

@ -1,4 +1,4 @@
**Improvements** (29 items) **Improvements** (30 items)
If you have suggestions for improvements, then please [raise an issue in this repository](https://github.com/markjprice/cs11dotnet7/issues) or email me at markjprice (at) gmail.com. If you have suggestions for improvements, then please [raise an issue in this repository](https://github.com/markjprice/cs11dotnet7/issues) or email me at markjprice (at) gmail.com.
@ -11,6 +11,7 @@ If you have suggestions for improvements, then please [raise an issue in this re
- [Page 161 - Using lambdas in function implementations](#page-161---using-lambdas-in-function-implementations) - [Page 161 - Using lambdas in function implementations](#page-161---using-lambdas-in-function-implementations)
- [Page 179 - Reviewing project packages](#page-179---reviewing-project-packages) - [Page 179 - Reviewing project packages](#page-179---reviewing-project-packages)
- [Page 200 - Talking about OOP](#page-200---talking-about-oop) - [Page 200 - Talking about OOP](#page-200---talking-about-oop)
- [Page 235 - More about methods](#page-235---more-about-methods)
- [Page 237 - Implementing functionality using methods](#page-237---implementing-functionality-using-methods) - [Page 237 - Implementing functionality using methods](#page-237---implementing-functionality-using-methods)
- [Page 241 - Defining flight passengers](#page-241---defining-flight-passengers) - [Page 241 - Defining flight passengers](#page-241---defining-flight-passengers)
- [Page 251 - Setting up a class library and console application](#page-251---setting-up-a-class-library-and-console-application) - [Page 251 - Setting up a class library and console application](#page-251---setting-up-a-class-library-and-console-application)
@ -235,6 +236,129 @@ interface ITheta { void M3() { } void M4(); }
class Iota : ITheta { void M4() { } } class Iota : ITheta { void M4() { } }
``` ```
# Page 235 - More about methods
> Thanks to [cgwid](https://github.com/cgwid) for raising this [issue on 12 April 2023](https://github.com/markjprice/cs11dotnet7/issues/59).
In this section, we define some methods and operators so that two `Person` objects can get married and have babies. The example we model comes from the Bible story of Lamech and his two wives and their children. But the code I tell you to write does not allow Lamech to marry two women so later an exception is thrown when Lamech and his second wife try to make a baby.
cgwid suggested a solution in [the issue they raised](https://github.com/markjprice/cs11dotnet7/issues/59).
Here is my possible improvement. I might change it before using it in the next edition. We could use a `List<Person>` to store the zero, one or more people that a `Person` is married too. We could implement `Married` as a readonly property that calls the LINQ `Any` method to return `true` if there are any items in the `Spouses` list, as shown in the following code:
```cs
// Is this person married to anyone?
public bool Married => Spouses.Any();
// Allow multiple spouses.
public List<Person> Spouses = new();
```
Then we can implement the `static Marry` method by checking if the person is already in the list and then adding them if they are not, as shown in the following code:
```cs
// static method to marry
public static void Marry(Person p1, Person p2)
{
if (p1.Spouses.Contains(p2) || p2.Spouses.Contains(p1))
{
throw new ArgumentException(
string.Format("{0} is already married to {1}.",
arg0: p1.Name, arg1: p2.Name));
}
else
{
p1.Spouses.Add(p2);
p2.Spouses.Add(p1);
}
}
// instance method to marry
public void Marry(Person partner)
{
Marry(this, partner);
}
```
For convenience, we could create a method to output the number of and names of spouses of the current person, as shown in the following code:
```cs
public void OutputSpouses()
{
if (Married)
{
string term = Spouses.Count == 1 ? "person" : "people";
WriteLine($"{Name} is married to {Spouses.Count} {term}:");
foreach (Person spouse in Spouses)
{
WriteLine($" {spouse.Name}");
}
}
else
{
WriteLine($"{Name} is not married.");
}
}
```
We would also need to change the `Procreate` method to check that the two people are married before allowing them to make a baby, as shown in the following code:
```cs
// static method to "multiply"
public static Person Procreate(Person p1, Person p2)
{
if (!p1.Spouses.Contains(p2))
{
throw new ArgumentException(
string.Format("{0} must be married to {1} to procreate with them.",
arg0: p1.Name, arg1: p2.Name));
}
Person baby = new()
{
Name = $"Baby of {p1.Name} and {p2.Name}",
DateOfBirth = DateTime.Now
};
p1.Children.Add(baby);
p2.Children.Add(baby);
return baby;
}
```
Finally, we can call the `OutputSpouses` method in `Program.cs`, as shown in the following code:
```cs
// Implementing functionality using methods
Person lamech = new() { Name = "Lamech" };
Person adah = new() { Name = "Adah" };
Person zillah = new() { Name = "Zillah" };
lamech.Marry(adah);
// Person.Marry(zillah, lamech);
if (zillah + lamech)
{
WriteLine($"{zillah.Name} and {lamech.Name} successfully got married.");
}
else
{
WriteLine($"{zillah.Name} and {lamech.Name} failed to marry.");
}
lamech.OutputSpouses();
adah.OutputSpouses();
zillah.OutputSpouses();
```
The output should look like this:
```
Zillah and Lamech successfully got married.
Lamech is married to 2 people:
Adah
Zillah
Adah is married to 1 person:
Lamech
Zillah is married to 1 person:
Lamech
```
# Page 237 - Implementing functionality using methods # Page 237 - Implementing functionality using methods
> Thanks to [Masoud Nazari](https://github.com/MAS-OUD) for raising this [issue on 5 March 2023](https://github.com/markjprice/cs11dotnet7/issues/35). > Thanks to [Masoud Nazari](https://github.com/MAS-OUD) for raising this [issue on 5 March 2023](https://github.com/markjprice/cs11dotnet7/issues/35).

View file

@ -74,33 +74,59 @@ public partial class Person
} }
} }
private bool married = false; // Is this person married to anyone?
public bool Married => married; public bool Married => Spouses.Any();
private Person? spouse = null; // Allow multiple spouses.
public Person? Spouse => spouse; public List<Person> Spouses = new();
// static method to marry // static method to marry
public static void Marry(Person p1, Person p2) public static void Marry(Person p1, Person p2)
{ {
p1.Marry(p2); if (p1.Spouses.Contains(p2) || p2.Spouses.Contains(p1))
{
throw new ArgumentException(
string.Format("{0} is already married to {1}.",
arg0: p1.Name, arg1: p2.Name));
}
else
{
p1.Spouses.Add(p2);
p2.Spouses.Add(p1);
}
} }
// instance method to marry // instance method to marry
public void Marry(Person partner) public void Marry(Person partner)
{ {
if (married) return; Marry(this, partner);
spouse = partner; }
married = true;
partner.Marry(this); // this is the current object public void OutputSpouses()
{
if (Married)
{
string term = Spouses.Count == 1 ? "person" : "people";
WriteLine($"{Name} is married to {Spouses.Count} {term}:");
foreach (Person spouse in Spouses)
{
WriteLine($" {spouse.Name}");
}
}
else
{
WriteLine($"{Name} is not married.");
}
} }
// static method to "multiply" // static method to "multiply"
public static Person Procreate(Person p1, Person p2) public static Person Procreate(Person p1, Person p2)
{ {
if (p1.Spouse != p2) if (!p1.Spouses.Contains(p2))
{ {
throw new ArgumentException("You must be married to procreate."); throw new ArgumentException(
string.Format("{0} must be married to {1} to procreate with them.",
arg0: p1.Name, arg1: p2.Name));
} }
Person baby = new() Person baby = new()

View file

@ -211,14 +211,19 @@ Person zillah = new() { Name = "Zillah" };
lamech.Marry(adah); lamech.Marry(adah);
// Person.Marry(zillah, lamech); // Person.Marry(zillah, lamech);
if (zillah + lamech) if (zillah + lamech)
{ {
WriteLine($"{zillah.Name} and {lamech.Name} successfully got married."); WriteLine($"{zillah.Name} and {lamech.Name} successfully got married.");
} }
else
{
WriteLine($"{zillah.Name} and {lamech.Name} failed to marry.");
}
WriteLine($"{lamech.Name} is married to {lamech.Spouse?.Name ?? "nobody"}"); lamech.OutputSpouses();
WriteLine($"{adah.Name} is married to {adah.Spouse?.Name ?? "nobody"}"); adah.OutputSpouses();
WriteLine($"{zillah.Name} is married to {zillah.Spouse?.Name ?? "nobody"}"); zillah.OutputSpouses();
// call instance method // call instance method
Person baby1 = lamech.ProcreateWith(adah); Person baby1 = lamech.ProcreateWith(adah);
@ -248,7 +253,7 @@ for (int i = 0; i < lamech.Children.Count; i++)
// Implementing functionality using local functions // Implementing functionality using local functions
int number = -1; // change to -1 to make the exception handling code execute int number = 6; // change to -1 to make the exception handling code execute
try try
{ {

View file

@ -74,33 +74,59 @@ public partial class Person
} }
} }
private bool married = false; // Is this person married to anyone?
public bool Married => married; public bool Married => Spouses.Any();
private Person? spouse = null; // Allow multiple spouses.
public Person? Spouse => spouse; public List<Person> Spouses = new();
// static method to marry // static method to marry
public static void Marry(Person p1, Person p2) public static void Marry(Person p1, Person p2)
{ {
p1.Marry(p2); if (p1.Spouses.Contains(p2) || p2.Spouses.Contains(p1))
{
throw new ArgumentException(
string.Format("{0} is already married to {1}.",
arg0: p1.Name, arg1: p2.Name));
}
else
{
p1.Spouses.Add(p2);
p2.Spouses.Add(p1);
}
} }
// instance method to marry // instance method to marry
public void Marry(Person partner) public void Marry(Person partner)
{ {
if (married) return; Marry(this, partner);
spouse = partner; }
married = true;
partner.Marry(this); // this is the current object public void OutputSpouses()
{
if (Married)
{
string term = Spouses.Count == 1 ? "person" : "people";
WriteLine($"{Name} is married to {Spouses.Count} {term}:");
foreach (Person spouse in Spouses)
{
WriteLine($" {spouse.Name}");
}
}
else
{
WriteLine($"{Name} is not married.");
}
} }
// static method to "multiply" // static method to "multiply"
public static Person Procreate(Person p1, Person p2) public static Person Procreate(Person p1, Person p2)
{ {
if (p1.Spouse != p2) if (!p1.Spouses.Contains(p2))
{ {
throw new ArgumentException("You must be married to procreate."); throw new ArgumentException(
string.Format("{0} must be married to {1} to procreate with them.",
arg0: p1.Name, arg1: p2.Name));
} }
Person baby = new() Person baby = new()

View file

@ -211,14 +211,19 @@ Person zillah = new() { Name = "Zillah" };
lamech.Marry(adah); lamech.Marry(adah);
// Person.Marry(zillah, lamech); // Person.Marry(zillah, lamech);
if (zillah + lamech) if (zillah + lamech)
{ {
WriteLine($"{zillah.Name} and {lamech.Name} successfully got married."); WriteLine($"{zillah.Name} and {lamech.Name} successfully got married.");
} }
else
{
WriteLine($"{zillah.Name} and {lamech.Name} failed to marry.");
}
WriteLine($"{lamech.Name} is married to {lamech.Spouse?.Name ?? "nobody"}"); lamech.OutputSpouses();
WriteLine($"{adah.Name} is married to {adah.Spouse?.Name ?? "nobody"}"); adah.OutputSpouses();
WriteLine($"{zillah.Name} is married to {zillah.Spouse?.Name ?? "nobody"}"); zillah.OutputSpouses();
// call instance method // call instance method
Person baby1 = lamech.ProcreateWith(adah); Person baby1 = lamech.ProcreateWith(adah);
@ -248,7 +253,7 @@ for (int i = 0; i < lamech.Children.Count; i++)
// Implementing functionality using local functions // Implementing functionality using local functions
int number = -1; // change to -1 to make the exception handling code execute int number = 6; // change to -1 to make the exception handling code execute
try try
{ {