diff --git a/vs4win/Chapter04/CalculatorLib/Calculator.cs b/vs4win/Chapter04/CalculatorLib/Calculator.cs
new file mode 100644
index 0000000..9dc6c89
--- /dev/null
+++ b/vs4win/Chapter04/CalculatorLib/Calculator.cs
@@ -0,0 +1,10 @@
+namespace CalculatorLib
+{
+ public class Calculator
+ {
+ public double Add(double a, double b)
+ {
+ return a + b;
+ }
+ }
+}
\ No newline at end of file
diff --git a/vs4win/Chapter04/CalculatorLib/CalculatorLib.csproj b/vs4win/Chapter04/CalculatorLib/CalculatorLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vs4win/Chapter04/CalculatorLib/CalculatorLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj b/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj
new file mode 100644
index 0000000..7f1fa4b
--- /dev/null
+++ b/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net7.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs b/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs
new file mode 100644
index 0000000..5e6128e
--- /dev/null
+++ b/vs4win/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs
@@ -0,0 +1,35 @@
+using CalculatorLib;
+
+namespace CalculatorLibUnitTests
+{
+ public class CalculatorUnitTests
+ {
+ [Fact]
+ public void TestAdding2And2()
+ {
+ // arrange
+ double a = 2;
+ double b = 2;
+ double expected = 4;
+ Calculator calc = new();
+ // act
+ double actual = calc.Add(a, b);
+ // assert
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void TestAdding2And3()
+ {
+ // arrange
+ double a = 2;
+ double b = 3;
+ double expected = 5;
+ Calculator calc = new();
+ // act
+ double actual = calc.Add(a, b);
+ // assert
+ Assert.Equal(expected, actual);
+ }
+ }
+}
\ No newline at end of file
diff --git a/vs4win/Chapter04/CalculatorLibUnitTests/Usings.cs b/vs4win/Chapter04/CalculatorLibUnitTests/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/vs4win/Chapter04/CalculatorLibUnitTests/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/vs4win/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj b/vs4win/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj
new file mode 100644
index 0000000..197b64c
--- /dev/null
+++ b/vs4win/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/vs4win/Chapter04/CallStackExceptionHandling/Program.cs b/vs4win/Chapter04/CallStackExceptionHandling/Program.cs
new file mode 100644
index 0000000..12746c0
--- /dev/null
+++ b/vs4win/Chapter04/CallStackExceptionHandling/Program.cs
@@ -0,0 +1,25 @@
+using CallStackExceptionHandlingLib;
+using static System.Console;
+
+WriteLine("In Main");
+Alpha();
+
+void Alpha()
+{
+ WriteLine("In Alpha");
+ Beta();
+}
+
+void Beta()
+{
+ WriteLine("In Beta");
+ try
+ {
+ Calculator.Gamma();
+ }
+ catch (Exception ex)
+ {
+ WriteLine($"Caught this: {ex.Message}");
+ throw ex;
+ }
+}
diff --git a/vs4win/Chapter04/CallStackExceptionHandlingLib/Calculator.cs b/vs4win/Chapter04/CallStackExceptionHandlingLib/Calculator.cs
new file mode 100644
index 0000000..748d4dd
--- /dev/null
+++ b/vs4win/Chapter04/CallStackExceptionHandlingLib/Calculator.cs
@@ -0,0 +1,19 @@
+using static System.Console;
+
+namespace CallStackExceptionHandlingLib
+{
+ public class Calculator
+ {
+ public static void Gamma() // public so it can be called from outside
+ {
+ WriteLine("In Gamma");
+ Delta();
+ }
+
+ private static void Delta() // private so it can only be called internally
+ {
+ WriteLine("In Delta");
+ File.OpenText("bad file path");
+ }
+ }
+}
diff --git a/vs4win/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj b/vs4win/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vs4win/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj b/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj
new file mode 100644
index 0000000..95b2a42
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+ preview
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs b/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs
new file mode 100644
index 0000000..b0a492a
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs
@@ -0,0 +1,10 @@
+using Ch04Ex02PrimeFactorsLib;
+
+Write("Enter a number between 1 and 1000: ");
+
+if (int.TryParse(ReadLine(), out int number))
+{
+ WriteLine(format: "Prime factors of {0} are: {1}",
+ arg0: number,
+ arg1: Primes.PrimeFactors(number));
+}
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj b/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs b/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs
new file mode 100644
index 0000000..f8f4281
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs
@@ -0,0 +1,39 @@
+namespace Ch04Ex02PrimeFactorsLib
+{
+ public class Primes
+ {
+ public static int[] PrimeNumbers = new[]
+ {
+ 97, 89, 83, 79, 73, 71, 67, 61, 59, 53,
+ 47, 43, 41, 37, 31, 29, 23, 19, 17, 13,
+ 11, 7, 5, 3, 2
+ };
+
+ public static string PrimeFactors(int number)
+ {
+ string factors = string.Empty;
+
+ foreach (int divisor in PrimeNumbers)
+ {
+ int remainder;
+ do
+ {
+ remainder = number % divisor;
+ if (remainder == 0)
+ {
+ number = number / divisor;
+ if (number == 1)
+ {
+ factors += $"{divisor}";
+ }
+ else
+ {
+ factors += $"{divisor} x ";
+ }
+ }
+ } while (remainder == 0);
+ }
+ return $"{factors}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj
new file mode 100644
index 0000000..2ac4e3d
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs
new file mode 100644
index 0000000..4f88eba
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs
@@ -0,0 +1,35 @@
+using Ch04Ex02PrimeFactorsLib;
+
+namespace Ch04Ex02PrimeFactorsTests
+{
+ public class PrimeFactorsUnitTests
+ {
+ [Fact]
+ public void PrimeFactorsOf40()
+ {
+ // arrange
+ int number = 40;
+ string expected = "5 x 2 x 2 x 2";
+
+ // act
+ string actual = Primes.PrimeFactors(number);
+
+ // assert
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void PrimeFactorsOf99()
+ {
+ // arrange
+ int number = 99;
+ string expected = "11 x 3 x 3";
+
+ // act
+ string actual = Primes.PrimeFactors(number);
+
+ // assert
+ Assert.Equal(expected, actual);
+ }
+ }
+}
diff --git a/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/vs4win/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/vs4win/Chapter04/Chapter04.sln b/vs4win/Chapter04/Chapter04.sln
new file mode 100644
index 0000000..da1dca3
--- /dev/null
+++ b/vs4win/Chapter04/Chapter04.sln
@@ -0,0 +1,79 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32210.238
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WritingFunctions", "WritingFunctions\WritingFunctions.csproj", "{59DFA8EE-F2D8-40A0-8E17-EB249443B109}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Debugging", "Debugging\Debugging.csproj", "{4FC54815-4A47-4B64-B3BF-BABE64AA7D2D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Instrumenting", "Instrumenting\Instrumenting.csproj", "{8061BFA7-C0A6-48BD-BE64-64501621429C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CalculatorLib", "CalculatorLib\CalculatorLib.csproj", "{07863BDC-DBD6-4714-9A98-59A6930ECB6F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CalculatorLibUnitTests", "CalculatorLibUnitTests\CalculatorLibUnitTests.csproj", "{6F3D5375-6D85-4A79-97A2-3605347BE4BE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallStackExceptionHandlingLib", "CallStackExceptionHandlingLib\CallStackExceptionHandlingLib.csproj", "{B6B0B88B-66E7-4599-ABA8-E9DC9BF2EF57}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CallStackExceptionHandling", "CallStackExceptionHandling\CallStackExceptionHandling.csproj", "{B856E873-E17A-400D-98B5-165C3DF976AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch04Ex02PrimeFactorsApp", "Ch04Ex02PrimeFactorsApp\Ch04Ex02PrimeFactorsApp.csproj", "{3B2B2F8A-FCB9-4C9D-85EE-D2433213D771}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch04Ex02PrimeFactorsLib", "Ch04Ex02PrimeFactorsLib\Ch04Ex02PrimeFactorsLib.csproj", "{5BD87DA8-3F4B-4CF7-A225-3E7030A1944C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch04Ex02PrimeFactorsTests", "Ch04Ex02PrimeFactorsTests\Ch04Ex02PrimeFactorsTests.csproj", "{878F1F7E-D3AD-4BF2-A66E-4EDDE7229566}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {59DFA8EE-F2D8-40A0-8E17-EB249443B109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {59DFA8EE-F2D8-40A0-8E17-EB249443B109}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {59DFA8EE-F2D8-40A0-8E17-EB249443B109}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {59DFA8EE-F2D8-40A0-8E17-EB249443B109}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4FC54815-4A47-4B64-B3BF-BABE64AA7D2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4FC54815-4A47-4B64-B3BF-BABE64AA7D2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4FC54815-4A47-4B64-B3BF-BABE64AA7D2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4FC54815-4A47-4B64-B3BF-BABE64AA7D2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8061BFA7-C0A6-48BD-BE64-64501621429C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8061BFA7-C0A6-48BD-BE64-64501621429C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8061BFA7-C0A6-48BD-BE64-64501621429C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8061BFA7-C0A6-48BD-BE64-64501621429C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07863BDC-DBD6-4714-9A98-59A6930ECB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07863BDC-DBD6-4714-9A98-59A6930ECB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07863BDC-DBD6-4714-9A98-59A6930ECB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07863BDC-DBD6-4714-9A98-59A6930ECB6F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6F3D5375-6D85-4A79-97A2-3605347BE4BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F3D5375-6D85-4A79-97A2-3605347BE4BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F3D5375-6D85-4A79-97A2-3605347BE4BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F3D5375-6D85-4A79-97A2-3605347BE4BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B6B0B88B-66E7-4599-ABA8-E9DC9BF2EF57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B6B0B88B-66E7-4599-ABA8-E9DC9BF2EF57}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B6B0B88B-66E7-4599-ABA8-E9DC9BF2EF57}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B6B0B88B-66E7-4599-ABA8-E9DC9BF2EF57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B856E873-E17A-400D-98B5-165C3DF976AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B856E873-E17A-400D-98B5-165C3DF976AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B856E873-E17A-400D-98B5-165C3DF976AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B856E873-E17A-400D-98B5-165C3DF976AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B2B2F8A-FCB9-4C9D-85EE-D2433213D771}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B2B2F8A-FCB9-4C9D-85EE-D2433213D771}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B2B2F8A-FCB9-4C9D-85EE-D2433213D771}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B2B2F8A-FCB9-4C9D-85EE-D2433213D771}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5BD87DA8-3F4B-4CF7-A225-3E7030A1944C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5BD87DA8-3F4B-4CF7-A225-3E7030A1944C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5BD87DA8-3F4B-4CF7-A225-3E7030A1944C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5BD87DA8-3F4B-4CF7-A225-3E7030A1944C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {878F1F7E-D3AD-4BF2-A66E-4EDDE7229566}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {878F1F7E-D3AD-4BF2-A66E-4EDDE7229566}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {878F1F7E-D3AD-4BF2-A66E-4EDDE7229566}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {878F1F7E-D3AD-4BF2-A66E-4EDDE7229566}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DF0D726D-6818-48B7-9F87-CBE3EA568974}
+ EndGlobalSection
+EndGlobal
diff --git a/vs4win/Chapter04/Debugging/Debugging.csproj b/vs4win/Chapter04/Debugging/Debugging.csproj
new file mode 100644
index 0000000..61f4e03
--- /dev/null
+++ b/vs4win/Chapter04/Debugging/Debugging.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/vs4win/Chapter04/Debugging/Program.cs b/vs4win/Chapter04/Debugging/Program.cs
new file mode 100644
index 0000000..910c058
--- /dev/null
+++ b/vs4win/Chapter04/Debugging/Program.cs
@@ -0,0 +1,12 @@
+double a = 4.5;
+double b = 2.5;
+double answer = Add(a, b);
+
+WriteLine($"{a} + {b} = {answer}");
+WriteLine("Press ENTER to end the app.");
+ReadLine(); // wait for user to press ENTER
+
+double Add(double a, double b)
+{
+ return a + b; // deliberate bug!
+}
diff --git a/vs4win/Chapter04/Instrumenting/Instrumenting.csproj b/vs4win/Chapter04/Instrumenting/Instrumenting.csproj
new file mode 100644
index 0000000..b879c25
--- /dev/null
+++ b/vs4win/Chapter04/Instrumenting/Instrumenting.csproj
@@ -0,0 +1,23 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/vs4win/Chapter04/Instrumenting/Program.cs b/vs4win/Chapter04/Instrumenting/Program.cs
new file mode 100644
index 0000000..3460f77
--- /dev/null
+++ b/vs4win/Chapter04/Instrumenting/Program.cs
@@ -0,0 +1,43 @@
+using System.Diagnostics;
+using Microsoft.Extensions.Configuration;
+
+string logPath = Path.Combine(Environment.GetFolderPath(
+ Environment.SpecialFolder.DesktopDirectory), "log.txt");
+
+Console.WriteLine($"Writing to: {logPath}");
+
+TextWriterTraceListener logFile = new(File.CreateText(logPath));
+
+Trace.Listeners.Add(logFile);
+
+// text writer is buffered, so this option calls
+// Flush() on all listeners after writing
+Trace.AutoFlush = true;
+
+Debug.WriteLine("Debug says, I am watching!");
+Trace.WriteLine("Trace says, I am watching!");
+
+Console.WriteLine("Reading from appsettings.json in {0}",
+ arg0: Directory.GetCurrentDirectory());
+
+ConfigurationBuilder builder = new();
+
+builder.SetBasePath(Directory.GetCurrentDirectory());
+
+builder.AddJsonFile("appsettings.json",
+ optional: false, reloadOnChange: true);
+
+IConfigurationRoot configuration = builder.Build();
+
+TraceSwitch ts = new(
+ displayName: "PacktSwitch",
+ description: "This switch is set via a JSON config.");
+
+configuration.GetSection("PacktSwitch").Bind(ts);
+
+Trace.WriteLineIf(ts.TraceError, "Trace error");
+Trace.WriteLineIf(ts.TraceWarning, "Trace warning");
+Trace.WriteLineIf(ts.TraceInfo, "Trace information");
+Trace.WriteLineIf(ts.TraceVerbose, "Trace verbose");
+
+Console.ReadLine();
\ No newline at end of file
diff --git a/vs4win/Chapter04/Instrumenting/appsettings.json b/vs4win/Chapter04/Instrumenting/appsettings.json
new file mode 100644
index 0000000..37790aa
--- /dev/null
+++ b/vs4win/Chapter04/Instrumenting/appsettings.json
@@ -0,0 +1,5 @@
+{
+ "PacktSwitch": {
+ "Level": "Info"
+ }
+}
diff --git a/vs4win/Chapter04/WritingFunctions/Program.Functions.cs b/vs4win/Chapter04/WritingFunctions/Program.Functions.cs
new file mode 100644
index 0000000..8297031
--- /dev/null
+++ b/vs4win/Chapter04/WritingFunctions/Program.Functions.cs
@@ -0,0 +1,170 @@
+partial class Program
+{
+ static void TimesTable(byte number, byte size = 12)
+ {
+ WriteLine($"This is the {number} times table with {size} rows:");
+ for (int row = 1; row <= size; row++)
+ {
+ WriteLine($"{row} x {number} = {row * number}");
+ }
+ WriteLine();
+ }
+
+ static decimal CalculateTax(
+ decimal amount, string twoLetterRegionCode)
+ {
+ decimal rate = 0.0M;
+
+ switch (twoLetterRegionCode)
+ {
+ case "CH": // Switzerland
+ rate = 0.08M;
+ break;
+ case "DK": // Denmark
+ case "NO": // Norway
+ rate = 0.25M;
+ break;
+ case "GB": // United Kingdom
+ case "FR": // France
+ rate = 0.2M;
+ break;
+ case "HU": // Hungary
+ rate = 0.27M;
+ break;
+ case "OR": // Oregon
+ case "AK": // Alaska
+ case "MT": // Montana
+ rate = 0.0M;
+ break;
+ case "ND": // North Dakota
+ case "WI": // Wisconsin
+ case "ME": // Maine
+ case "VA": // Virginia
+ rate = 0.05M;
+ break;
+ case "CA": // California
+ rate = 0.0825M;
+ break;
+ default: // most US states
+ rate = 0.06M;
+ break;
+ }
+ return amount * rate;
+ }
+
+ ///
+ /// Pass a 32-bit integer and it will be converted into its ordinal equivalent.
+ ///
+ /// Number is a cardinal value e.g. 1, 2, 3, and so on.
+ /// Number as an ordinal value e.g. 1st, 2nd, 3rd, and so on.
+
+ static string CardinalToOrdinal(int number)
+ {
+ switch (number)
+ {
+ case 11: // special cases for 11th to 13th
+ case 12:
+ case 13:
+ return $"{number}th";
+ default:
+ int lastDigit = number % 10;
+ string suffix = lastDigit switch
+ {
+ 1 => "st",
+ 2 => "nd",
+ 3 => "rd",
+ _ => "th"
+ };
+ return $"{number}{suffix}";
+ }
+ }
+
+ static void RunCardinalToOrdinal()
+ {
+ for (int number = 1; number <= 40; number++)
+ {
+ Write($"{CardinalToOrdinal(number)} ");
+ }
+ WriteLine();
+ }
+
+ static int Factorial(int number)
+ {
+ if (number < 0)
+ {
+ throw new ArgumentException(message:
+ "The factorial function is defined for non-negative integers only.",
+ paramName: "number");
+ }
+ else if (number == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ checked // for overflow
+ {
+ return number * Factorial(number - 1);
+ }
+ }
+ }
+
+ static void RunFactorial()
+ {
+ for (int i = 1; i <= 14; i++)
+ {
+ try
+ {
+ WriteLine($"{i}! = {Factorial(i):N0}");
+ }
+ catch (System.OverflowException)
+ {
+ WriteLine($"{i}! is too big for a 32-bit integer.");
+ }
+ }
+ }
+
+ static int FibImperative(int term)
+ {
+ if (term == 1)
+ {
+ return 0;
+ }
+ else if (term == 2)
+ {
+ return 1;
+ }
+ else
+ {
+ return FibImperative(term - 1) + FibImperative(term - 2);
+ }
+ }
+ static void RunFibImperative()
+ {
+ for (int i = 1; i <= 30; i++)
+ {
+ WriteLine("The {0} term of the Fibonacci sequence is {1:N0}.",
+ arg0: CardinalToOrdinal(i),
+ arg1: FibImperative(term: i));
+ }
+ }
+
+ static int FibFunctional(int term) =>
+ term switch
+ {
+ 1 => 0,
+ 2 => 1,
+ _ => FibFunctional(term - 1) + FibFunctional(term - 2)
+ };
+
+ static void RunFibFunctional()
+ {
+ for (int i = 1; i <= 30; i++)
+ {
+ WriteLine("The {0} term of the Fibonacci sequence is {1:N0}.",
+ arg0: CardinalToOrdinal(i),
+ arg1: FibFunctional(term: i));
+ }
+ }
+
+}
diff --git a/vs4win/Chapter04/WritingFunctions/Program.cs b/vs4win/Chapter04/WritingFunctions/Program.cs
new file mode 100644
index 0000000..f2a87e5
--- /dev/null
+++ b/vs4win/Chapter04/WritingFunctions/Program.cs
@@ -0,0 +1,20 @@
+/*
+TimesTable(7);
+
+TimesTable(7, 20);
+
+TimesTable(number: 7, size: 10);
+*/
+
+/*
+decimal taxToPay = CalculateTax(amount: 149, twoLetterRegionCode: "FR");
+WriteLine($"You must pay {taxToPay} in tax.");
+*/
+
+//RunCardinalToOrdinal();
+
+//RunFactorial();
+
+//RunFibImperative();
+
+RunFibFunctional();
\ No newline at end of file
diff --git a/vs4win/Chapter04/WritingFunctions/WritingFunctions.csproj b/vs4win/Chapter04/WritingFunctions/WritingFunctions.csproj
new file mode 100644
index 0000000..05635b2
--- /dev/null
+++ b/vs4win/Chapter04/WritingFunctions/WritingFunctions.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/CalculatorLib/Calculator.cs b/vscode/Chapter04/CalculatorLib/Calculator.cs
new file mode 100644
index 0000000..9dc6c89
--- /dev/null
+++ b/vscode/Chapter04/CalculatorLib/Calculator.cs
@@ -0,0 +1,10 @@
+namespace CalculatorLib
+{
+ public class Calculator
+ {
+ public double Add(double a, double b)
+ {
+ return a + b;
+ }
+ }
+}
\ No newline at end of file
diff --git a/vscode/Chapter04/CalculatorLib/CalculatorLib.csproj b/vscode/Chapter04/CalculatorLib/CalculatorLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vscode/Chapter04/CalculatorLib/CalculatorLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vscode/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj b/vscode/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj
new file mode 100644
index 0000000..7f1fa4b
--- /dev/null
+++ b/vscode/Chapter04/CalculatorLibUnitTests/CalculatorLibUnitTests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net7.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs b/vscode/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs
new file mode 100644
index 0000000..5e6128e
--- /dev/null
+++ b/vscode/Chapter04/CalculatorLibUnitTests/CalculatorUnitTests.cs
@@ -0,0 +1,35 @@
+using CalculatorLib;
+
+namespace CalculatorLibUnitTests
+{
+ public class CalculatorUnitTests
+ {
+ [Fact]
+ public void TestAdding2And2()
+ {
+ // arrange
+ double a = 2;
+ double b = 2;
+ double expected = 4;
+ Calculator calc = new();
+ // act
+ double actual = calc.Add(a, b);
+ // assert
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void TestAdding2And3()
+ {
+ // arrange
+ double a = 2;
+ double b = 3;
+ double expected = 5;
+ Calculator calc = new();
+ // act
+ double actual = calc.Add(a, b);
+ // assert
+ Assert.Equal(expected, actual);
+ }
+ }
+}
\ No newline at end of file
diff --git a/vscode/Chapter04/CalculatorLibUnitTests/Usings.cs b/vscode/Chapter04/CalculatorLibUnitTests/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/vscode/Chapter04/CalculatorLibUnitTests/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/vscode/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj b/vscode/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj
new file mode 100644
index 0000000..197b64c
--- /dev/null
+++ b/vscode/Chapter04/CallStackExceptionHandling/CallStackExceptionHandling.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/CallStackExceptionHandling/Program.cs b/vscode/Chapter04/CallStackExceptionHandling/Program.cs
new file mode 100644
index 0000000..12746c0
--- /dev/null
+++ b/vscode/Chapter04/CallStackExceptionHandling/Program.cs
@@ -0,0 +1,25 @@
+using CallStackExceptionHandlingLib;
+using static System.Console;
+
+WriteLine("In Main");
+Alpha();
+
+void Alpha()
+{
+ WriteLine("In Alpha");
+ Beta();
+}
+
+void Beta()
+{
+ WriteLine("In Beta");
+ try
+ {
+ Calculator.Gamma();
+ }
+ catch (Exception ex)
+ {
+ WriteLine($"Caught this: {ex.Message}");
+ throw ex;
+ }
+}
diff --git a/vscode/Chapter04/CallStackExceptionHandlingLib/Calculator.cs b/vscode/Chapter04/CallStackExceptionHandlingLib/Calculator.cs
new file mode 100644
index 0000000..748d4dd
--- /dev/null
+++ b/vscode/Chapter04/CallStackExceptionHandlingLib/Calculator.cs
@@ -0,0 +1,19 @@
+using static System.Console;
+
+namespace CallStackExceptionHandlingLib
+{
+ public class Calculator
+ {
+ public static void Gamma() // public so it can be called from outside
+ {
+ WriteLine("In Gamma");
+ Delta();
+ }
+
+ private static void Delta() // private so it can only be called internally
+ {
+ WriteLine("In Delta");
+ File.OpenText("bad file path");
+ }
+ }
+}
diff --git a/vscode/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj b/vscode/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vscode/Chapter04/CallStackExceptionHandlingLib/CallStackExceptionHandlingLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj b/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj
new file mode 100644
index 0000000..95b2a42
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Ch04Ex02PrimeFactorsApp.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+ preview
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs b/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs
new file mode 100644
index 0000000..b0a492a
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsApp/Program.cs
@@ -0,0 +1,10 @@
+using Ch04Ex02PrimeFactorsLib;
+
+Write("Enter a number between 1 and 1000: ");
+
+if (int.TryParse(ReadLine(), out int number))
+{
+ WriteLine(format: "Prime factors of {0} are: {1}",
+ arg0: number,
+ arg1: Primes.PrimeFactors(number));
+}
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj b/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj
new file mode 100644
index 0000000..cfadb03
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Ch04Ex02PrimeFactorsLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs b/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs
new file mode 100644
index 0000000..f8f4281
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsLib/Primes.cs
@@ -0,0 +1,39 @@
+namespace Ch04Ex02PrimeFactorsLib
+{
+ public class Primes
+ {
+ public static int[] PrimeNumbers = new[]
+ {
+ 97, 89, 83, 79, 73, 71, 67, 61, 59, 53,
+ 47, 43, 41, 37, 31, 29, 23, 19, 17, 13,
+ 11, 7, 5, 3, 2
+ };
+
+ public static string PrimeFactors(int number)
+ {
+ string factors = string.Empty;
+
+ foreach (int divisor in PrimeNumbers)
+ {
+ int remainder;
+ do
+ {
+ remainder = number % divisor;
+ if (remainder == 0)
+ {
+ number = number / divisor;
+ if (number == 1)
+ {
+ factors += $"{divisor}";
+ }
+ else
+ {
+ factors += $"{divisor} x ";
+ }
+ }
+ } while (remainder == 0);
+ }
+ return $"{factors}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj
new file mode 100644
index 0000000..2ac4e3d
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Ch04Ex02PrimeFactorsTests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs
new file mode 100644
index 0000000..4f88eba
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/PrimeFactorsUnitTests.cs
@@ -0,0 +1,35 @@
+using Ch04Ex02PrimeFactorsLib;
+
+namespace Ch04Ex02PrimeFactorsTests
+{
+ public class PrimeFactorsUnitTests
+ {
+ [Fact]
+ public void PrimeFactorsOf40()
+ {
+ // arrange
+ int number = 40;
+ string expected = "5 x 2 x 2 x 2";
+
+ // act
+ string actual = Primes.PrimeFactors(number);
+
+ // assert
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void PrimeFactorsOf99()
+ {
+ // arrange
+ int number = 99;
+ string expected = "11 x 3 x 3";
+
+ // act
+ string actual = Primes.PrimeFactors(number);
+
+ // assert
+ Assert.Equal(expected, actual);
+ }
+ }
+}
diff --git a/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/vscode/Chapter04/Ch04Ex02PrimeFactorsTests/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/vscode/Chapter04/Chapter04.code-workspace b/vscode/Chapter04/Chapter04.code-workspace
new file mode 100644
index 0000000..e23c290
--- /dev/null
+++ b/vscode/Chapter04/Chapter04.code-workspace
@@ -0,0 +1,19 @@
+{
+ "folders": [
+ {
+ "path": "WritingFunctions"
+ },
+ {
+ "path": "Debugging"
+ },
+ {
+ "path": "Instrumenting"
+ },
+ {
+ "path": "CalculatorLib"
+ },
+ {
+ "path": "CalculatorLibUnitTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/vscode/Chapter04/Debugging/Debugging.csproj b/vscode/Chapter04/Debugging/Debugging.csproj
new file mode 100644
index 0000000..61f4e03
--- /dev/null
+++ b/vscode/Chapter04/Debugging/Debugging.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/vscode/Chapter04/Debugging/Program.cs b/vscode/Chapter04/Debugging/Program.cs
new file mode 100644
index 0000000..910c058
--- /dev/null
+++ b/vscode/Chapter04/Debugging/Program.cs
@@ -0,0 +1,12 @@
+double a = 4.5;
+double b = 2.5;
+double answer = Add(a, b);
+
+WriteLine($"{a} + {b} = {answer}");
+WriteLine("Press ENTER to end the app.");
+ReadLine(); // wait for user to press ENTER
+
+double Add(double a, double b)
+{
+ return a + b; // deliberate bug!
+}
diff --git a/vscode/Chapter04/Instrumenting/Instrumenting.csproj b/vscode/Chapter04/Instrumenting/Instrumenting.csproj
new file mode 100644
index 0000000..b879c25
--- /dev/null
+++ b/vscode/Chapter04/Instrumenting/Instrumenting.csproj
@@ -0,0 +1,23 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/vscode/Chapter04/Instrumenting/Program.cs b/vscode/Chapter04/Instrumenting/Program.cs
new file mode 100644
index 0000000..3460f77
--- /dev/null
+++ b/vscode/Chapter04/Instrumenting/Program.cs
@@ -0,0 +1,43 @@
+using System.Diagnostics;
+using Microsoft.Extensions.Configuration;
+
+string logPath = Path.Combine(Environment.GetFolderPath(
+ Environment.SpecialFolder.DesktopDirectory), "log.txt");
+
+Console.WriteLine($"Writing to: {logPath}");
+
+TextWriterTraceListener logFile = new(File.CreateText(logPath));
+
+Trace.Listeners.Add(logFile);
+
+// text writer is buffered, so this option calls
+// Flush() on all listeners after writing
+Trace.AutoFlush = true;
+
+Debug.WriteLine("Debug says, I am watching!");
+Trace.WriteLine("Trace says, I am watching!");
+
+Console.WriteLine("Reading from appsettings.json in {0}",
+ arg0: Directory.GetCurrentDirectory());
+
+ConfigurationBuilder builder = new();
+
+builder.SetBasePath(Directory.GetCurrentDirectory());
+
+builder.AddJsonFile("appsettings.json",
+ optional: false, reloadOnChange: true);
+
+IConfigurationRoot configuration = builder.Build();
+
+TraceSwitch ts = new(
+ displayName: "PacktSwitch",
+ description: "This switch is set via a JSON config.");
+
+configuration.GetSection("PacktSwitch").Bind(ts);
+
+Trace.WriteLineIf(ts.TraceError, "Trace error");
+Trace.WriteLineIf(ts.TraceWarning, "Trace warning");
+Trace.WriteLineIf(ts.TraceInfo, "Trace information");
+Trace.WriteLineIf(ts.TraceVerbose, "Trace verbose");
+
+Console.ReadLine();
\ No newline at end of file
diff --git a/vscode/Chapter04/Instrumenting/appsettings.json b/vscode/Chapter04/Instrumenting/appsettings.json
new file mode 100644
index 0000000..37790aa
--- /dev/null
+++ b/vscode/Chapter04/Instrumenting/appsettings.json
@@ -0,0 +1,5 @@
+{
+ "PacktSwitch": {
+ "Level": "Info"
+ }
+}
diff --git a/vscode/Chapter04/WritingFunctions/Program.Functions.cs b/vscode/Chapter04/WritingFunctions/Program.Functions.cs
new file mode 100644
index 0000000..8297031
--- /dev/null
+++ b/vscode/Chapter04/WritingFunctions/Program.Functions.cs
@@ -0,0 +1,170 @@
+partial class Program
+{
+ static void TimesTable(byte number, byte size = 12)
+ {
+ WriteLine($"This is the {number} times table with {size} rows:");
+ for (int row = 1; row <= size; row++)
+ {
+ WriteLine($"{row} x {number} = {row * number}");
+ }
+ WriteLine();
+ }
+
+ static decimal CalculateTax(
+ decimal amount, string twoLetterRegionCode)
+ {
+ decimal rate = 0.0M;
+
+ switch (twoLetterRegionCode)
+ {
+ case "CH": // Switzerland
+ rate = 0.08M;
+ break;
+ case "DK": // Denmark
+ case "NO": // Norway
+ rate = 0.25M;
+ break;
+ case "GB": // United Kingdom
+ case "FR": // France
+ rate = 0.2M;
+ break;
+ case "HU": // Hungary
+ rate = 0.27M;
+ break;
+ case "OR": // Oregon
+ case "AK": // Alaska
+ case "MT": // Montana
+ rate = 0.0M;
+ break;
+ case "ND": // North Dakota
+ case "WI": // Wisconsin
+ case "ME": // Maine
+ case "VA": // Virginia
+ rate = 0.05M;
+ break;
+ case "CA": // California
+ rate = 0.0825M;
+ break;
+ default: // most US states
+ rate = 0.06M;
+ break;
+ }
+ return amount * rate;
+ }
+
+ ///
+ /// Pass a 32-bit integer and it will be converted into its ordinal equivalent.
+ ///
+ /// Number is a cardinal value e.g. 1, 2, 3, and so on.
+ /// Number as an ordinal value e.g. 1st, 2nd, 3rd, and so on.
+
+ static string CardinalToOrdinal(int number)
+ {
+ switch (number)
+ {
+ case 11: // special cases for 11th to 13th
+ case 12:
+ case 13:
+ return $"{number}th";
+ default:
+ int lastDigit = number % 10;
+ string suffix = lastDigit switch
+ {
+ 1 => "st",
+ 2 => "nd",
+ 3 => "rd",
+ _ => "th"
+ };
+ return $"{number}{suffix}";
+ }
+ }
+
+ static void RunCardinalToOrdinal()
+ {
+ for (int number = 1; number <= 40; number++)
+ {
+ Write($"{CardinalToOrdinal(number)} ");
+ }
+ WriteLine();
+ }
+
+ static int Factorial(int number)
+ {
+ if (number < 0)
+ {
+ throw new ArgumentException(message:
+ "The factorial function is defined for non-negative integers only.",
+ paramName: "number");
+ }
+ else if (number == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ checked // for overflow
+ {
+ return number * Factorial(number - 1);
+ }
+ }
+ }
+
+ static void RunFactorial()
+ {
+ for (int i = 1; i <= 14; i++)
+ {
+ try
+ {
+ WriteLine($"{i}! = {Factorial(i):N0}");
+ }
+ catch (System.OverflowException)
+ {
+ WriteLine($"{i}! is too big for a 32-bit integer.");
+ }
+ }
+ }
+
+ static int FibImperative(int term)
+ {
+ if (term == 1)
+ {
+ return 0;
+ }
+ else if (term == 2)
+ {
+ return 1;
+ }
+ else
+ {
+ return FibImperative(term - 1) + FibImperative(term - 2);
+ }
+ }
+ static void RunFibImperative()
+ {
+ for (int i = 1; i <= 30; i++)
+ {
+ WriteLine("The {0} term of the Fibonacci sequence is {1:N0}.",
+ arg0: CardinalToOrdinal(i),
+ arg1: FibImperative(term: i));
+ }
+ }
+
+ static int FibFunctional(int term) =>
+ term switch
+ {
+ 1 => 0,
+ 2 => 1,
+ _ => FibFunctional(term - 1) + FibFunctional(term - 2)
+ };
+
+ static void RunFibFunctional()
+ {
+ for (int i = 1; i <= 30; i++)
+ {
+ WriteLine("The {0} term of the Fibonacci sequence is {1:N0}.",
+ arg0: CardinalToOrdinal(i),
+ arg1: FibFunctional(term: i));
+ }
+ }
+
+}
diff --git a/vscode/Chapter04/WritingFunctions/Program.cs b/vscode/Chapter04/WritingFunctions/Program.cs
new file mode 100644
index 0000000..f2a87e5
--- /dev/null
+++ b/vscode/Chapter04/WritingFunctions/Program.cs
@@ -0,0 +1,20 @@
+/*
+TimesTable(7);
+
+TimesTable(7, 20);
+
+TimesTable(number: 7, size: 10);
+*/
+
+/*
+decimal taxToPay = CalculateTax(amount: 149, twoLetterRegionCode: "FR");
+WriteLine($"You must pay {taxToPay} in tax.");
+*/
+
+//RunCardinalToOrdinal();
+
+//RunFactorial();
+
+//RunFibImperative();
+
+RunFibFunctional();
\ No newline at end of file
diff --git a/vscode/Chapter04/WritingFunctions/WritingFunctions.csproj b/vscode/Chapter04/WritingFunctions/WritingFunctions.csproj
new file mode 100644
index 0000000..05635b2
--- /dev/null
+++ b/vscode/Chapter04/WritingFunctions/WritingFunctions.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+