diff --git a/src/Chapter09.Tests/GlobalUsing.cs b/src/Chapter09.Tests/GlobalUsing.cs new file mode 100644 index 000000000..057ac5d09 --- /dev/null +++ b/src/Chapter09.Tests/GlobalUsing.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/src/Chapter09.Tests/Listing09.01.Tests.cs b/src/Chapter09.Tests/Listing09.01.Tests.cs new file mode 100644 index 000000000..bc718eca6 --- /dev/null +++ b/src/Chapter09.Tests/Listing09.01.Tests.cs @@ -0,0 +1,29 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01.Tests; + +[TestClass] +public class AngleTests +{ + [TestMethod] + public void Create_AngleArray_ElementsAreUninitialized() + { + Angle angle = default; + Angle[] angles = new Angle[1]; + Assert.AreEqual(angle, angles[0]); + } + + [TestMethod] + public void Equals_CopyWithSameDegreesMinutesSeconds_AreEqual() + { + Angle angle1 = new(0, 0, 0); + Angle angle2 = new(0, 0, 0); + Assert.AreEqual(angle1, angle2); + } + + [TestMethod] + public void With_CopyWithSameDegreesMinutesSeconds_AreEqual() + { + Angle angle1 = new(0, 0, 0); + Angle angle2 = angle1 with { }; + Assert.AreEqual(angle1, angle2); + } +} diff --git a/src/Chapter09.Tests/Listing09.02.Tests.cs b/src/Chapter09.Tests/Listing09.02.Tests.cs new file mode 100644 index 000000000..5a812d97f --- /dev/null +++ b/src/Chapter09.Tests/Listing09.02.Tests.cs @@ -0,0 +1,15 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_02.Tests; + +[TestClass] +public class AngleProgramTests +{ + [TestMethod] + public void Create_Angle_Success() + { + string expected = + "Angle { Degrees = 90, Minutes = 0, Seconds = 0, Name = }"; + IntelliTect.TestTools.Console.ConsoleAssert.Expect( + expected, Program.Main); + } + +} diff --git a/src/Chapter09.Tests/Listing09.04.DeclaringRecordClass.Tests.cs b/src/Chapter09.Tests/Listing09.04.DeclaringRecordClass.Tests.cs new file mode 100644 index 000000000..71344a376 --- /dev/null +++ b/src/Chapter09.Tests/Listing09.04.DeclaringRecordClass.Tests.cs @@ -0,0 +1,93 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04.Tests; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_07; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public partial class CoordinateTests +{ + [TestMethod] + public void With_Coordinate_IsReadOnly() + { + Coordinate coordinate1 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + Coordinate coordinate2 = coordinate1 with { }; + + Assert.AreEqual(coordinate1, coordinate2); + } + + [TestMethod] + public void EqualityContract_GetType() + { + Coordinate coordinate1 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + NamedCoordinate coordinate2 = new( + coordinate1.Longitude, coordinate1.Latitude, "Test"); + + + Assert.AreNotEqual(coordinate1.GetType(), coordinate2.GetType()); + } + + record struct SampleStruct(int A, int B) + { + int C { get; set; } + } + + [TestMethod] + public void GetHashCode_ChangeData_GetHashCodeChanges() + { + SampleStruct sample1 = new(1, 2); + int expected = sample1.GetHashCode(); + sample1.A = 3; + Assert.AreNotEqual(expected, sample1.GetHashCode()); + } + + + [TestMethod] + public void GetHashCode_StoredInDictionary_NotFoundWhenChanged() + { + SampleStruct sample = new(1, 2); + Dictionary dictionary = new() { { sample, "" } }; + sample.A = 3; + Assert.IsFalse(dictionary.ContainsKey(sample)); + } + + + [TestMethod] + public void GetHashCode_OnTuplesStoredInDictionary_NotFoundWhenChanged() + { + (int A, int B) tuple = new(1, 2); + Dictionary<(int A, int B), string> dictionary = new() { { tuple, "" } }; + tuple.A = 3; + Assert.IsFalse(dictionary.ContainsKey(tuple)); + } + + [TestMethod] + public void ToString_GivenAdditionalProperty_IgnoredInOutput() + { + SampleStruct sampleStruct = new(1, 2); + Assert.AreEqual("SampleStruct { A = 1, B = 2 }", sampleStruct.ToString()); + } + + [TestMethod] + public void With_Instance_Equivalent() + { + Coordinate coordinate1 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + Coordinate coordinate2 = coordinate1 with { }; + Assert.AreEqual(coordinate1, coordinate2); + } + + [TestMethod] + public void With_DifferentInstance_NotEquivalent() + { + Coordinate coordinate1 = + new(new Angle(180, 0, 0), new Angle(180, 0, 0)); + Angle angle = new Angle(0, 0, 0); + Coordinate coordinate2 = coordinate1 with + { + Latitude = angle + }; + Assert.AreNotEqual(coordinate1, coordinate2); + } +} diff --git a/src/Chapter09.Tests/Listing09.05.EquivalentRecordClassCode.Tests.cs b/src/Chapter09.Tests/Listing09.05.EquivalentRecordClassCode.Tests.cs new file mode 100644 index 000000000..c626ba241 --- /dev/null +++ b/src/Chapter09.Tests/Listing09.05.EquivalentRecordClassCode.Tests.cs @@ -0,0 +1,33 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_05.Tests; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_07; + +[TestClass] +public class CoordinateTests +{ + [TestMethod] + public void With_Coordinate_IsReadOnly() + { + Coordinate coordinate1 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + Coordinate coordinate2 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + + Assert.AreEqual(coordinate1, coordinate2); + } + + [TestMethod] + public void EqualityContract_GetType() + { + Coordinate coordinate1 = new( + new Angle(180, 0, 0), new Angle(180, 0, 0)); + NamedCoordinate geoCoordinate = new( + new Angle(180, 0, 0), new Angle(180, 0, 0), "GeoCoordinate"); + + Assert.AreEqual(coordinate1.ExternalEqualityContract, coordinate1.GetType()); + + Assert.AreEqual(geoCoordinate.ExternalEqualityContract, geoCoordinate.GetType()); + Assert.AreEqual(((Coordinate)geoCoordinate).ExternalEqualityContract, ((Coordinate)geoCoordinate).GetType()); + } +} diff --git a/src/Chapter09.Tests/Listing09.08.CustomizingARecord.Tests.cs b/src/Chapter09.Tests/Listing09.08.CustomizingARecord.Tests.cs new file mode 100644 index 000000000..8cdeb5564 --- /dev/null +++ b/src/Chapter09.Tests/Listing09.08.CustomizingARecord.Tests.cs @@ -0,0 +1,32 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_08.Tests; + +[TestClass] +public class AngleTests +{ + [TestMethod] + public void ToString_90Degrees_90DegreesFormatted() + { + string expected = $"90° 0' 0\""; + string actual = new Angle(90, 0, 0).ToString(); + Assert.AreEqual( + expected, + actual); + } + [TestMethod] + public void ToString_90DegreesWithName_90DegreesFormatted() + { + string expected = $"RightAngle: 90° 0' 0\""; + string actual = new Angle(90, 0, 0, "RightAngle").ToString(); + Assert.AreEqual( + expected, + actual); + } + + [TestMethod] + public void Equals_CopyWithSameDegreesMinutesSecondsBut_AreEqual() + { + Angle angle1 = new(0,0,0, "90 degrees"); + Angle angle2 = new(0, 0, 0); + Assert.AreEqual(angle1, angle2); + } +} diff --git a/src/Chapter09.Tests/Listing09.04.SubtleBoxAndUnboxInstructions.Tests.cs b/src/Chapter09.Tests/Listing09.09.SubtleBoxAndUnboxInstructions.Tests.cs similarity index 93% rename from src/Chapter09.Tests/Listing09.04.SubtleBoxAndUnboxInstructions.Tests.cs rename to src/Chapter09.Tests/Listing09.09.SubtleBoxAndUnboxInstructions.Tests.cs index 9cbd31ecb..55fcfd076 100644 --- a/src/Chapter09.Tests/Listing09.04.SubtleBoxAndUnboxInstructions.Tests.cs +++ b/src/Chapter09.Tests/Listing09.09.SubtleBoxAndUnboxInstructions.Tests.cs @@ -1,6 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_09.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09.Tests/Listing09.06.SubtleBoxingIdiosyncrasies.Tests.cs b/src/Chapter09.Tests/Listing09.11.SubtleBoxingIdiosyncrasies.Tests.cs similarity index 82% rename from src/Chapter09.Tests/Listing09.06.SubtleBoxingIdiosyncrasies.Tests.cs rename to src/Chapter09.Tests/Listing09.11.SubtleBoxingIdiosyncrasies.Tests.cs index 2e59c3f57..71fb67828 100644 --- a/src/Chapter09.Tests/Listing09.06.SubtleBoxingIdiosyncrasies.Tests.cs +++ b/src/Chapter09.Tests/Listing09.11.SubtleBoxingIdiosyncrasies.Tests.cs @@ -1,6 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_06.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_11.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09.Tests/Listing09.07.AvoidingUnboxingAndCopying.Tests.cs b/src/Chapter09.Tests/Listing09.12.AvoidingUnboxingAndCopying.Tests.cs similarity index 82% rename from src/Chapter09.Tests/Listing09.07.AvoidingUnboxingAndCopying.Tests.cs rename to src/Chapter09.Tests/Listing09.12.AvoidingUnboxingAndCopying.Tests.cs index d043354af..d0b768f56 100644 --- a/src/Chapter09.Tests/Listing09.07.AvoidingUnboxingAndCopying.Tests.cs +++ b/src/Chapter09.Tests/Listing09.12.AvoidingUnboxingAndCopying.Tests.cs @@ -1,6 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_07.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_12.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09.Tests/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.Tests.cs b/src/Chapter09.Tests/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.Tests.cs deleted file mode 100644 index e17766dc5..000000000 --- a/src/Chapter09.Tests/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.Tests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_12.Tests; - -[TestClass] -public class ProgramTests -{ - [TestMethod] - public void Main_CastThreadLevelPriorityEnumToString() - { - const string expected = "Idle"; - - IntelliTect.TestTools.Console.ConsoleAssert.Expect( - expected, Program.Main); - } -} diff --git a/src/Chapter09.Tests/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs b/src/Chapter09.Tests/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs similarity index 83% rename from src/Chapter09.Tests/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs rename to src/Chapter09.Tests/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs index 0197c3409..822353290 100644 --- a/src/Chapter09.Tests/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs +++ b/src/Chapter09.Tests/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.Tests.cs @@ -1,6 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_13.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_17.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09.Tests/Listing09.15.UsingBitwiseORandANDWithFlagEnums.Tests.cs b/src/Chapter09.Tests/Listing09.19.UsingBitwiseORandANDWithFlagEnums.Tests.cs similarity index 93% rename from src/Chapter09.Tests/Listing09.15.UsingBitwiseORandANDWithFlagEnums.Tests.cs rename to src/Chapter09.Tests/Listing09.19.UsingBitwiseORandANDWithFlagEnums.Tests.cs index 46402b68a..7b36235f4 100644 --- a/src/Chapter09.Tests/Listing09.15.UsingBitwiseORandANDWithFlagEnums.Tests.cs +++ b/src/Chapter09.Tests/Listing09.19.UsingBitwiseORandANDWithFlagEnums.Tests.cs @@ -1,7 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Runtime.InteropServices; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_15.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_19.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09.Tests/Listing09.17.UsingFlagsAttribute.Tests.cs b/src/Chapter09.Tests/Listing09.21.UsingFlagsAttribute.Tests.cs similarity index 90% rename from src/Chapter09.Tests/Listing09.17.UsingFlagsAttribute.Tests.cs rename to src/Chapter09.Tests/Listing09.21.UsingFlagsAttribute.Tests.cs index 34b22c849..a1e2e7d7c 100644 --- a/src/Chapter09.Tests/Listing09.17.UsingFlagsAttribute.Tests.cs +++ b/src/Chapter09.Tests/Listing09.21.UsingFlagsAttribute.Tests.cs @@ -1,7 +1,6 @@ using System.Runtime.InteropServices; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_17.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_21.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter09/Listing09.01.BasicStruct.cs b/src/Chapter09/Listing09.01.BasicStruct.cs new file mode 100644 index 000000000..ba4d2bd2a --- /dev/null +++ b/src/Chapter09/Listing09.01.BasicStruct.cs @@ -0,0 +1,7 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; + +#region INCLUDE +// Use the record struct construct to declare a value type +public readonly record struct Angle( + int Degrees, int Minutes, int Seconds, string? Name = null); +#endregion INCLUDE \ No newline at end of file diff --git a/src/Chapter09/Listing09.01.DeclaringAStruct.cs b/src/Chapter09/Listing09.01.DeclaringAStruct.cs deleted file mode 100644 index 8ad9d186d..000000000 --- a/src/Chapter09/Listing09.01.DeclaringAStruct.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01 -{ - #region INCLUDE - // Use keyword struct to declare a value type - #region HIGHLIGHT - readonly public struct Angle - #endregion HIGHLIGHT - { - public Angle(int degrees, int minutes, int seconds) - { - Degrees = degrees; - Minutes = minutes; - Seconds = seconds; - } - - public int Degrees { get; } - public int Minutes { get; } - public int Seconds { get; } - - public Angle Move(int degrees, int minutes, int seconds) - { - return new Angle( - Degrees + degrees, - Minutes + minutes, - Seconds + seconds); - } - } - - // Declaring a class as a reference type - // (declaring it as a struct would create a value type - // larger than 16 bytes.) - class Coordinate - { - public Angle Longitude { get; set; } - - public Angle Latitude { get; set; } - } - #endregion INCLUDE -} \ No newline at end of file diff --git a/src/Chapter09/Listing09.02.InitializingAStructFieldWithinADeclarationResultingInAnError.cs b/src/Chapter09/Listing09.02.InitializingAStructFieldWithinADeclarationResultingInAnError.cs deleted file mode 100644 index 3414a1a9f..000000000 --- a/src/Chapter09/Listing09.02.InitializingAStructFieldWithinADeclarationResultingInAnError.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_02 -{ - // Use keyword struct to declare a value type - #region INCLUDE - struct Angle - { - #region EXCLUDE - public Angle(int degrees, int minutes, int seconds) - { - Degrees = degrees; - Minutes = minutes; - Seconds = seconds; - } - #endregion EXCLUDE - // ERROR: Fields cannot be initialized at declaration time - // private int _Degrees = 42; - #region EXCLUDE - public int Degrees { get; } - - public int Minutes { get; } - public int Seconds { get; } - - public Angle Move(int degrees, int minutes, int seconds) - { - return new Angle( - Degrees + degrees, - Minutes + minutes, - Seconds + seconds); - } - #endregion EXCLUDE - } - #endregion INCLUDE - - // Declaring a class as a reference type - // (declaring it as a struct would create a value type - // larger than 16 bytes.) - class Coordinate - { - public Angle Longitude - { - get { return _Longitude; } - set { _Longitude = value; } - } - private Angle _Longitude; - - public Angle Latitude - { - get { return _Latitude; } - set { _Latitude = value; } - } - private Angle _Latitude; - } -} \ No newline at end of file diff --git a/src/Chapter09/Listing09.02.ProgrammingWithARecordStruct.cs b/src/Chapter09/Listing09.02.ProgrammingWithARecordStruct.cs new file mode 100644 index 000000000..784491fa9 --- /dev/null +++ b/src/Chapter09/Listing09.02.ProgrammingWithARecordStruct.cs @@ -0,0 +1,47 @@ + +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_02; + +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; +#region INCLUDE +using System.Diagnostics; + +public class Program +{ + public static void Main() + { + (int degrees, int minutes, int seconds) = ( + 90, 0, 0); + + // The constructor is generated using positional parameters + Angle angle = new(degrees, minutes, seconds); + + // Records include a ToString() implementation + // that returns: + // "Angle { Degrees = 90, Minutes = 0, Seconds = 0, Name = }" + Console.WriteLine(angle.ToString()); + + // Records have a deconstructor using the + // positional parameters. + if (angle is (int, int, int, string) angleData) + { + Trace.Assert(angle.Degrees == angleData.Degrees); + Trace.Assert(angle.Minutes == angleData.Minutes); + Trace.Assert(angle.Seconds == angleData.Seconds); + } + + Angle copy = new(degrees, minutes, seconds); + // Records provide a custom equality operator. + Trace.Assert(angle == copy); + + // The with operator is the equivalent of + // Angle copy = new(degrees, minutes, seconds); + copy = angle with { }; + Trace.Assert(angle == copy); + + // The with operator has object initializer type + // syntax for instantiating a modified copy. + Angle modifiedCopy = angle with { Degrees = 180 }; + Trace.Assert(angle != modifiedCopy); + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.03.AccessingPropertiesBeforeInitializingAllFields.cs b/src/Chapter09/Listing09.03.AccessingPropertiesBeforeInitializingAllFields.cs deleted file mode 100644 index e2be57565..000000000 --- a/src/Chapter09/Listing09.03.AccessingPropertiesBeforeInitializingAllFields.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_03 -{ - // Use keyword struct to declare a value type - #region INCLUDE - struct Angle - { - // ERROR: The 'this' object cannot be used before - // all of its fields are assigned to - // public Angle(int degrees, int minutes, int seconds) - // { - #region HIGHLIGHT - // Degrees = degrees; // Shorthand for this.Hours = hours; - // Minutes = minutes; // Shorthand for this.Minutes = ...; - // Seconds = seconds; // Shorthand for this.Seconds = ...; - #endregion HIGHLIGHT - // } - - public Angle(int degrees, int minutes, int seconds) - { - _Degrees = degrees; // Shorthand for this.Degrees = ...; - _Minutes = minutes; // Shorthand for this.Minutes = ...; - _Seconds = seconds; // Shorthand for this.Seconds = ...; - } - - public int Degrees { get { return _Degrees; } } - readonly private int _Degrees; - - public int Minutes { get { return _Minutes; } } - readonly private int _Minutes; - - public int Seconds { get { return _Seconds; } } - readonly private int _Seconds; - - #region EXCLUDE - public Angle Move(int degrees, int minutes, int seconds) - { - return new Angle( - Degrees + degrees, - Minutes + minutes, - Seconds + seconds); - } - #endregion EXCLUDE - } - #endregion INCLUDE - - // Declaring a class as a reference type - // (declaring it as a struct would create a value type - // larger than 16 bytes.) - class Coordinate - { - public Angle Longitude - { - get { return _Longitude; } - set { _Longitude = value; } - } - private Angle _Longitude; - - public Angle Latitude - { - get { return _Latitude; } - set { _Latitude = value; } - } - private Angle _Latitude; - } -} \ No newline at end of file diff --git a/src/Chapter09/Listing09.03.EquivalentRecordStructCode.cs b/src/Chapter09/Listing09.03.EquivalentRecordStructCode.cs new file mode 100644 index 000000000..84983ff55 --- /dev/null +++ b/src/Chapter09/Listing09.03.EquivalentRecordStructCode.cs @@ -0,0 +1,85 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_03; + + +#region INCLUDE +using System.Runtime.CompilerServices; +using System.Text; + +[CompilerGenerated] +public readonly struct Angle : IEquatable +{ + public int Degrees { get; init; } + public int Minutes { get; init; } + public int Seconds { get; init; } + public string? Name { get; init; } + + public Angle(int Degrees, int Minutes, int Seconds, string? Name) + { + this.Degrees = Degrees; + this.Minutes = Minutes; + this.Seconds = Seconds; + this.Name = Name; + } + + public override string ToString() + { + StringBuilder stringBuilder = new(); + stringBuilder.Append("Angle"); + stringBuilder.Append(" { "); + if (PrintMembers(stringBuilder)) + { + stringBuilder.Append(' '); + } + stringBuilder.Append('}'); + return stringBuilder.ToString(); + } + + private bool PrintMembers(StringBuilder builder) + { + builder.Append("Degrees = "); + builder.Append(Degrees); + builder.Append(", Minutes = "); + builder.Append(Minutes); + builder.Append(", Seconds = "); + builder.Append(Seconds); + builder.Append(", Name = "); + builder.Append(Name); + return true; + } + + public static bool operator !=(Angle left, Angle right) => + !(left == right); + + public static bool operator ==(Angle left, Angle right) => + left.Equals(right); + + public override int GetHashCode() + { + static int GetHashCode(int integer) => + EqualityComparer.Default.GetHashCode(integer); + + return GetHashCode(Degrees) * -1521134295 + + GetHashCode(Minutes) * -1521134295 + + GetHashCode(Seconds) * -1521134295 + + EqualityComparer.Default.GetHashCode(Name!); + } + + public override bool Equals(object? obj) => + obj is Angle angle && Equals(angle); + + public bool Equals(Angle other) => + EqualityComparer.Default.Equals(Degrees, other.Degrees) + && EqualityComparer.Default.Equals(Minutes, other.Minutes) + && EqualityComparer.Default.Equals(Seconds, other.Seconds) + && EqualityComparer.Default.Equals(Name, other.Name); + + public void Deconstruct( + out int Degrees, out int Minutes, out int Seconds, out string? Name) + { + Degrees = this.Degrees; + Minutes = this.Minutes; + Seconds = this.Seconds; + Name = this.Name; + } +} +#endregion INCLUDE \ No newline at end of file diff --git a/src/Chapter09/Listing09.04.DeclaringRecordClass.cs b/src/Chapter09/Listing09.04.DeclaringRecordClass.cs new file mode 100644 index 000000000..86df01243 --- /dev/null +++ b/src/Chapter09/Listing09.04.DeclaringRecordClass.cs @@ -0,0 +1,8 @@ +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; + +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04; + +public record class Coordinate(Angle Longitude, Angle Latitude) +{ + public Type ExternalEqualityContract => EqualityContract; +} diff --git a/src/Chapter09/Listing09.04.SubtleBoxAndUnboxInstructions.cs b/src/Chapter09/Listing09.04.SubtleBoxAndUnboxInstructions.cs deleted file mode 100644 index aa3db76e0..000000000 --- a/src/Chapter09/Listing09.04.SubtleBoxAndUnboxInstructions.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04 -{ - using System; - #region INCLUDE - public class DisplayFibonacci - { - public static void Main() - { - int totalCount; - // Intentionally using ArrayList to demonstrate boxing - System.Collections.ArrayList list = - new System.Collections.ArrayList(); - - Console.Write("Enter an integer between 2 and 1000: "); - string? inputText = Console.ReadLine(); - if (!int.TryParse(inputText, out totalCount)) - { - Console.WriteLine($"'{inputText}' is not a valid integer."); - return; - } - - if (totalCount == 7) // Magic number used for testing - { - // Triggers exception when retrieving value as double. - list.Add(0); // Cast to double or 'D' suffix required. - // Whether cast or using 'D' suffix, - // CIL is identical. - - } - else - { - list.Add((double)0); - } - - list.Add((double)1); - - for(int count = 2; count < totalCount; count++) - { - list.Add( - (double)list[count - 1]! + - (double)list[count - 2]!); - } - - // Using a foreach to clarify the box operation rather than - // Console.WriteLine(string.Join(", ", list.ToArray())); - foreach (double? count in list) - { - Console.Write("{0}, ", count); - } - } - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.05.EquivalentRecordClassCode.cs b/src/Chapter09/Listing09.05.EquivalentRecordClassCode.cs new file mode 100644 index 000000000..50a806c2d --- /dev/null +++ b/src/Chapter09/Listing09.05.EquivalentRecordClassCode.cs @@ -0,0 +1,95 @@ +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; + +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_05; +#region INCLUDE +using System.Runtime.CompilerServices; +using System.Text; + +[CompilerGenerated] +public class Coordinate : IEquatable +{ + + public Angle Longitude { get; init; } + public Angle Latitude { get; init; } + + public Coordinate(Angle Longitude, Angle Latitude) : + base() + { + this.Longitude = Longitude; + this.Latitude = Latitude; + } + + public override string ToString() + { + StringBuilder stringBuilder = new (); + stringBuilder.Append("Coordinate"); + stringBuilder.Append(" { "); + if (PrintMembers(stringBuilder)) + { + stringBuilder.Append(' '); + } + stringBuilder.Append('}'); + return stringBuilder.ToString(); + } + + protected virtual bool PrintMembers(StringBuilder builder) + { + RuntimeHelpers.EnsureSufficientExecutionStack(); + builder.Append("Longitude = "); + builder.Append(Longitude.ToString()); + builder.Append(", Latitude = "); + builder.Append(Latitude.ToString()); + return true; + } + + public static bool operator !=(Coordinate? left, Coordinate? right) => + !(left == right); + + public static bool operator ==(Coordinate? left, Coordinate? right) => + left == right || (left?.Equals(right) ?? false); + + public override int GetHashCode() + { + static int GetHashCode(Angle angle) => + EqualityComparer.Default.GetHashCode(angle); + + return (EqualityComparer.Default.GetHashCode( + EqualityContract()) * -1521134295 + + GetHashCode(Longitude)) * -1521134295 + + GetHashCode(Latitude); + } + + public override bool Equals(object? obj) => + Equals(obj as Coordinate); + + public virtual bool Equals(Coordinate? other) => + (object)this == other || (other is not null + && EqualityContract() == other!.EqualityContract() + && EqualityComparer.Default.Equals( + Longitude, other!.Longitude) + && EqualityComparer.Default.Equals( + Latitude, other!.Latitude)); + + public void Deconstruct(out Angle Longitude, out Angle Latitude) + { + Longitude = this.Longitude; + Latitude = this.Latitude; + } + + protected virtual Type EqualityContract() => typeof(Coordinate); + + public Type ExternalEqualityContract => EqualityContract(); + + + // Actual name in IL is "$". However, + // you can't add a Clone method to a record. + public Coordinate Clone() => new(this); + + protected Coordinate(Coordinate original) + { + Longitude = original.Longitude; + Latitude = original.Latitude; + } +} + +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.05.UnboxingMustBeToTheUnderlyingType.cs b/src/Chapter09/Listing09.05.UnboxingMustBeToTheUnderlyingType.cs deleted file mode 100644 index c0f42f7d0..000000000 --- a/src/Chapter09/Listing09.05.UnboxingMustBeToTheUnderlyingType.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_05 -{ - public class DisplayFibonacci - { - static void Main() - { - #region INCLUDE - // ... - - int number; - object thing; - double bigNumber; - - number = 42; - thing = number; - // ERROR: InvalidCastException - // bigNumber = (double)thing; - bigNumber = (double)(int)thing; - // ... - #endregion INCLUDE - } - } -} diff --git a/src/Chapter09/Listing09.06.SubtleBoxingIdiosyncrasies.cs b/src/Chapter09/Listing09.06.SubtleBoxingIdiosyncrasies.cs deleted file mode 100644 index cf08734fa..000000000 --- a/src/Chapter09/Listing09.06.SubtleBoxingIdiosyncrasies.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_06 -{ - using System; - - #region INCLUDE - interface IAngle - { - void MoveTo(int degrees, int minutes, int seconds); - } - - struct Angle : IAngle - { - #region EXCLUDE - public Angle(int degrees, int minutes, int seconds) - { - _Degrees = degrees; - _Minutes = minutes; - _Seconds = seconds; - } - #endregion EXCLUDE - - // NOTE: This makes Angle mutable, against the general - // guideline - public void MoveTo(int degrees, int minutes, int seconds) - { - _Degrees = degrees; - _Minutes = minutes; - _Seconds = seconds; - } - #region EXCLUDE - public int Degrees - { - get { return _Degrees; } - } - private int _Degrees; - - public int Minutes - { - get { return _Minutes; } - } - private int _Minutes; - - public int Seconds - { - get { return _Seconds; } - } - private int _Seconds; - #endregion EXCLUDE - } - public class Program - { - public static void Main() - { - // ... - - Angle angle = new Angle(25, 58, 23); - // Example 1: Simple box operation - object objectAngle = angle; // Box - Console.Write(((Angle)objectAngle).Degrees); - - // Example 2: Unbox, modify unboxed value, and discard value - ((Angle)objectAngle).MoveTo(26, 58, 23); - Console.Write(", " + ((Angle)objectAngle).Degrees); - - // Example 3: Box, modify boxed value, and discard reference to box - ((IAngle)angle).MoveTo(26, 58, 23); - Console.Write(", " + ((Angle)angle).Degrees); - - // Example 4: Modify boxed value directly - ((IAngle)objectAngle).MoveTo(26, 58, 23); - Console.WriteLine(", " + ((Angle)objectAngle).Degrees); - - // ... - } - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.06A.CloningRecordsViaWithOperator.cs b/src/Chapter09/Listing09.06A.CloningRecordsViaWithOperator.cs new file mode 100644 index 000000000..1a18c190c --- /dev/null +++ b/src/Chapter09/Listing09.06A.CloningRecordsViaWithOperator.cs @@ -0,0 +1,25 @@ + +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_06A; + +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; +#region INCLUDE +using System.Diagnostics; + +public class Program +{ + public static void Main() + { + Angle angle = new(90, 0, 0); + + // The with operator is the equivalent of + // Angle copy = new(degrees, minutes, seconds); + Angle copy = angle with { }; + Trace.Assert(angle == copy); + + // The with operator has object initializer type + // syntax for instantiating a modified copy. + Angle modifiedCopy = angle with { Degrees = 180 }; + Trace.Assert(angle != modifiedCopy); + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.07.AvoidingUnboxingAndCopying.cs b/src/Chapter09/Listing09.07.AvoidingUnboxingAndCopying.cs deleted file mode 100644 index 2ba59c454..000000000 --- a/src/Chapter09/Listing09.07.AvoidingUnboxingAndCopying.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_07 -{ - using System; - - public class Program - { - public static void Main() - { - #region INCLUDE - int number; - object thing; - number = 42; - // Boxing - thing = number; - #region HIGHLIGHT - // No unboxing conversion - #endregion HIGHLIGHT - string text = ((IFormattable)thing).ToString( - "X", null); - Console.WriteLine(text); - #endregion INCLUDE - } - } -} diff --git a/src/Chapter09/Listing09.07.RecordClassInheritance.cs b/src/Chapter09/Listing09.07.RecordClassInheritance.cs new file mode 100644 index 000000000..ece76736c --- /dev/null +++ b/src/Chapter09/Listing09.07.RecordClassInheritance.cs @@ -0,0 +1,9 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_07; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_01; +using AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_04; + +#region INCLUDE +public record class NamedCoordinate( + Angle Longitude, Angle Latitude, string Name) + : Coordinate(Longitude, Latitude); +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.08.ComparingAnIntegerSwitchToAnEnumSwitch.cs b/src/Chapter09/Listing09.08.ComparingAnIntegerSwitchToAnEnumSwitch.cs deleted file mode 100644 index 7afeca66f..000000000 --- a/src/Chapter09/Listing09.08.ComparingAnIntegerSwitchToAnEnumSwitch.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_08 -{ - using Listing09_10; - - public class Program - { - public static void SwitchInt() - { - #region INCLUDE - int connectionState; - #region EXCLUDE - // initialize connectionState for example - connectionState = 2; - #endregion EXCLUDE - switch (connectionState) - { - case 0: - // ... - break; - case 1: - // ... - break; - case 2: - // ... - break; - case 3: - // ... - break; - } - #region EXCLUDE - } - - public static void SwitchEnum() - { - #endregion EXCLUDE - ConnectionState connectionState; - #region EXCLUDE - // initialize connectionState for example - connectionState = ConnectionState.Connecting; - #endregion EXCLUDE - switch (connectionState) - { - case ConnectionState.Connected: - // ... - break; - case ConnectionState.Connecting: - // ... - break; - case ConnectionState.Disconnected: - // ... - break; - case ConnectionState.Disconnecting: - // ... - break; - } - #endregion INCLUDE - } - } -} diff --git a/src/Chapter09/Listing09.08.CustomizingARecord.cs b/src/Chapter09/Listing09.08.CustomizingARecord.cs new file mode 100644 index 000000000..645d59cc4 --- /dev/null +++ b/src/Chapter09/Listing09.08.CustomizingARecord.cs @@ -0,0 +1,38 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_08; + +#region INCLUDE +public readonly record struct Angle( + int Degrees, int Minutes, int Seconds, string? Name = null) +{ + + public int Degrees { get; } = Degrees; + + public Angle( + string degrees, string minutes, string seconds) + : this(int.Parse(degrees), + int.Parse(minutes), int.Parse(seconds)) + { + } + + public override readonly string ToString() + { + string prefix = + string.IsNullOrWhiteSpace(Name)?string.Empty : Name+": "; + return $"{prefix}{Degrees}° {Minutes}' {Seconds}\""; + } + + // Changing Equals() to ignore Name + public bool Equals(Angle other) => + (Degrees, Minutes, Seconds).Equals( + (other.Degrees, other.Minutes, other.Seconds)); + + public override int GetHashCode() => + HashCode.Combine(Degrees.GetHashCode(), + Minutes.GetHashCode(), Seconds.GetHashCode); + + #if UsingTupleToGenerateHashCode + public override int GetHashCode() => + (Degrees, Minutes, Seconds).GetHashCode(); + #endif // UsingTupleToGenerateHashCode +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.09.DefiningAnEnum.cs b/src/Chapter09/Listing09.09.DefiningAnEnum.cs deleted file mode 100644 index a74c73959..000000000 --- a/src/Chapter09/Listing09.09.DefiningAnEnum.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_09 -{ - #region INCLUDE - enum ConnectionState - { - Disconnected, - Connecting, - Connected, - Disconnecting - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.09.SubtleBoxAndUnboxInstructions.cs b/src/Chapter09/Listing09.09.SubtleBoxAndUnboxInstructions.cs new file mode 100644 index 000000000..5b96f3afe --- /dev/null +++ b/src/Chapter09/Listing09.09.SubtleBoxAndUnboxInstructions.cs @@ -0,0 +1,50 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_09; + +using System; +#region INCLUDE +public class DisplayFibonacci +{ + public static void Main() + { + // Intentionally using ArrayList to demonstrate boxing + System.Collections.ArrayList list = new(); + + Console.Write("Enter an integer between 2 and 1000: "); + string? inputText = Console.ReadLine(); + if (!int.TryParse(inputText, out int totalCount)) + { + Console.WriteLine($"'{inputText}' is not a valid integer."); + return; + } + + if (totalCount == 7) // Magic number used for testing + { + // Triggers exception when retrieving value as double. + list.Add(0); // Cast to double or 'D' suffix required. + // Whether cast or using 'D' suffix, + // CIL is identical. + + } + else + { + list.Add((double)0); + } + + list.Add((double)1); + + for(int count = 2; count < totalCount; count++) + { + list.Add( + (double)list[count - 1]! + + (double)list[count - 2]!); + } + + // Using a foreach to clarify the box operation rather than + // Console.WriteLine(string.Join(", ", list.ToArray())); + foreach (double? count in list) + { + Console.Write("{0}, ", count); + } + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.10.DefiningAnEnumType.cs b/src/Chapter09/Listing09.10.DefiningAnEnumType.cs deleted file mode 100644 index 972027eb1..000000000 --- a/src/Chapter09/Listing09.10.DefiningAnEnumType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_10 -{ - #region INCLUDE - enum ConnectionState : short - { - Disconnected, - Connecting = 10, - Connected, - Joined = Connected, - Disconnecting - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.10.UnboxingMustBeToTheUnderlyingType.cs b/src/Chapter09/Listing09.10.UnboxingMustBeToTheUnderlyingType.cs new file mode 100644 index 000000000..009ea6714 --- /dev/null +++ b/src/Chapter09/Listing09.10.UnboxingMustBeToTheUnderlyingType.cs @@ -0,0 +1,22 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_10; + +public class DisplayFibonacci +{ + static void Main() + { + #region INCLUDE + // ... + + int number; + object thing; + double bigNumber; + + number = 42; + thing = number; + // ERROR: InvalidCastException + // bigNumber = (double)thing; + bigNumber = (double)(int)thing; + // ... + #endregion INCLUDE + } +} diff --git a/src/Chapter09/Listing09.11.CastingBetweenArraysOfEnums.cs b/src/Chapter09/Listing09.11.CastingBetweenArraysOfEnums.cs deleted file mode 100644 index c42dc1997..000000000 --- a/src/Chapter09/Listing09.11.CastingBetweenArraysOfEnums.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_11 -{ - using System; - #region INCLUDE - enum ConnectionState1 - { - Disconnected, - Connecting, - Connected, - Disconnecting - } - - enum ConnectionState2 - { - Disconnected, - Connecting, - Connected, - Disconnecting - } - public class Program - { - public static void Main() - { - ConnectionState1[] states = - #region HIGHLIGHT - (ConnectionState1[])(Array)new ConnectionState2[42]; - #endregion HIGHLIGHT - } - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.11.SubtleBoxingIdiosyncrasies.cs b/src/Chapter09/Listing09.11.SubtleBoxingIdiosyncrasies.cs new file mode 100644 index 000000000..9b36e20ea --- /dev/null +++ b/src/Chapter09/Listing09.11.SubtleBoxingIdiosyncrasies.cs @@ -0,0 +1,79 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_11; + +using System; + +#region INCLUDE +interface IAngle +{ + void MoveTo(int degrees, int minutes, int seconds); +} + +struct Angle : IAngle +{ + #region EXCLUDE + public Angle(int degrees, int minutes, int seconds) + { + _Degrees = degrees; + _Minutes = minutes; + _Seconds = seconds; + } + #endregion EXCLUDE + + // NOTE: This makes Angle mutable, against the general + // guideline + public void MoveTo(int degrees, int minutes, int seconds) + { + _Degrees = degrees; + _Minutes = minutes; + _Seconds = seconds; + } + #region EXCLUDE + public int Degrees + { + get { return _Degrees; } + } + private int _Degrees; + + public int Minutes + { + get { return _Minutes; } + } + private int _Minutes; + + public int Seconds + { + get { return _Seconds; } + } + private int _Seconds; + #endregion EXCLUDE +} +public class Program +{ + public static void Main() + { + // ... + + Angle angle = new Angle(25, 58, 23); + // Example 1: Simple box operation + object objectAngle = angle; // Box + Console.Write(((Angle)objectAngle).Degrees); + + // Example 2: Unbox, modify unboxed value, + // and discard value + ((Angle)objectAngle).MoveTo + (26, 58, 23); + Console.Write(", " + ((Angle)objectAngle).Degrees); + + // Example 3: Box, modify boxed value, + // and discard reference to box + ((IAngle)angle).MoveTo(26, 58, 23); + Console.Write(", " + ((Angle)angle).Degrees); + + // Example 4: Modify boxed value directly + ((IAngle)objectAngle).MoveTo(26, 58, 23); + Console.WriteLine(", " + ((Angle)objectAngle).Degrees); + + // ... + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.12.AvoidingUnboxingAndCopying.cs b/src/Chapter09/Listing09.12.AvoidingUnboxingAndCopying.cs new file mode 100644 index 000000000..0aaca737d --- /dev/null +++ b/src/Chapter09/Listing09.12.AvoidingUnboxingAndCopying.cs @@ -0,0 +1,23 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_12; + +using System; + +public class Program +{ + public static void Main() + { + #region INCLUDE + int number; + object thing; + number = 42; + // Boxing + thing = number; + #region HIGHLIGHT + // No unboxing conversion + #endregion HIGHLIGHT + string text = ((IFormattable)thing).ToString( + "X", null); + Console.WriteLine(text); + #endregion INCLUDE + } +} diff --git a/src/Chapter09/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.cs b/src/Chapter09/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.cs deleted file mode 100644 index 3a91dc8f4..000000000 --- a/src/Chapter09/Listing09.12.ConvertingAStringToAnEnumUsingEnum.Parse.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_12 -{ - using System; - using System.Diagnostics; - - public class Program - { - public static void Main() - { - #region INCLUDE - ThreadPriorityLevel priority = (ThreadPriorityLevel)Enum.Parse( - typeof(ThreadPriorityLevel), "Idle"); - Console.WriteLine(priority); - #endregion INCLUDE - } - } -} diff --git a/src/Chapter09/Listing09.13.ComparingAnIntegerSwitchToAnEnumSwitch.cs b/src/Chapter09/Listing09.13.ComparingAnIntegerSwitchToAnEnumSwitch.cs new file mode 100644 index 000000000..986732131 --- /dev/null +++ b/src/Chapter09/Listing09.13.ComparingAnIntegerSwitchToAnEnumSwitch.cs @@ -0,0 +1,58 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_13; + +using Listing09_15; + +public class Program +{ + public static void SwitchInt() + { + #region INCLUDE + int connectionState; + #region EXCLUDE + // initialize connectionState for example + connectionState = 2; + #endregion EXCLUDE + switch (connectionState) + { + case 0: + // ... + break; + case 1: + // ... + break; + case 2: + // ... + break; + case 3: + // ... + break; + } + #region EXCLUDE + } + + public static void SwitchEnum() + { + #endregion EXCLUDE + ConnectionState connectionState; + #region EXCLUDE + // initialize connectionState for example + connectionState = ConnectionState.Connecting; + #endregion EXCLUDE + switch (connectionState) + { + case ConnectionState.Connected: + // ... + break; + case ConnectionState.Connecting: + // ... + break; + case ConnectionState.Disconnected: + // ... + break; + case ConnectionState.Disconnecting: + // ... + break; + } + #endregion INCLUDE + } +} diff --git a/src/Chapter09/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.cs b/src/Chapter09/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.cs deleted file mode 100644 index b8b009bad..000000000 --- a/src/Chapter09/Listing09.13.ConvertingAStringToAnEnumUsingEnum.TryParse.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_13 -{ - using System; - - public class Program - { - public static void Main() - { - #region INCLUDE - System.Diagnostics.ThreadPriorityLevel priority; - if(Enum.TryParse("Idle", out priority)) - { - Console.WriteLine(priority); - } - #endregion INCLUDE - } - } -} diff --git a/src/Chapter09/Listing09.14.DefiningAnEnum.cs b/src/Chapter09/Listing09.14.DefiningAnEnum.cs new file mode 100644 index 000000000..534de7f7e --- /dev/null +++ b/src/Chapter09/Listing09.14.DefiningAnEnum.cs @@ -0,0 +1,11 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_14; + +#region INCLUDE +enum ConnectionState +{ + Disconnected, + Connecting, + Connected, + Disconnecting +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.14.UsingEnumsAsFlags.cs b/src/Chapter09/Listing09.14.UsingEnumsAsFlags.cs deleted file mode 100644 index 7bca3dd71..000000000 --- a/src/Chapter09/Listing09.14.UsingEnumsAsFlags.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_14 -{ - using System; - - #region INCLUDE - [Flags] - public enum FileAttributes - { - None = 0, // 000000000000000 - ReadOnly = 1 << 0, // 000000000000001 - Hidden = 1 << 1, // 000000000000010 - System = 1 << 2, // 000000000000100 - Directory = 1 << 4, // 000000000010000 - Archive = 1 << 5, // 000000000100000 - Device = 1 << 6, // 000000001000000 - Normal = 1 << 7, // 000000010000000 - Temporary = 1 << 8, // 000000100000000 - SparseFile = 1 << 9, // 000001000000000 - ReparsePoint = 1 << 10, // 000010000000000 - Compressed = 1 << 11, // 000100000000000 - Offline = 1 << 12, // 001000000000000 - NotContentIndexed = 1 << 13, // 010000000000000 - Encrypted = 1 << 14, // 100000000000000 - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.15.DefiningAnEnumType.cs b/src/Chapter09/Listing09.15.DefiningAnEnumType.cs new file mode 100644 index 000000000..5d4929bf9 --- /dev/null +++ b/src/Chapter09/Listing09.15.DefiningAnEnumType.cs @@ -0,0 +1,12 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_15; + +#region INCLUDE +enum ConnectionState : short +{ + Disconnected, + Connecting = 10, + Connected, + Joined = Connected, + Disconnecting +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.15.UsingBitwiseORandANDWithFlagEnums.cs b/src/Chapter09/Listing09.15.UsingBitwiseORandANDWithFlagEnums.cs deleted file mode 100644 index 999857c06..000000000 --- a/src/Chapter09/Listing09.15.UsingBitwiseORandANDWithFlagEnums.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_15 -{ - #region INCLUDE - using System; - using System.IO; - - public class Program - { - public static void Main() - { - // ... - - string fileName = @"enumtest.txt"; - - #region EXCLUDE - System.IO.FileInfo enumFile = - new System.IO.FileInfo(fileName); - if (!enumFile.Exists) - { - enumFile.Create().Dispose(); - } - - try - { - #endregion EXCLUDE - System.IO.FileInfo file = - new System.IO.FileInfo(fileName); - - file.Attributes = FileAttributes.Hidden | - FileAttributes.ReadOnly; - - Console.WriteLine($"{file.Attributes} = {(int)file.Attributes}"); - - // Only the ReadOnly attribute works on Linux (The Hidden attribute does not work on Linux) - if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux)) - { - // Added in C# 4.0/Microsoft .NET Framework 4.0 - if (!file.Attributes.HasFlag(FileAttributes.Hidden)) - { - throw new Exception("File is not hidden."); - } - } - - if ((file.Attributes & FileAttributes.ReadOnly) != - FileAttributes.ReadOnly) - { - throw new Exception("File is not read-only."); - } - #region EXCLUDE - } - finally - { - if (enumFile.Exists) - { - enumFile.Attributes = FileAttributes.Normal; - enumFile.Delete(); - } - } - #endregion EXCLUDE - } - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.16.CastingBetweenArraysOfEnums.cs b/src/Chapter09/Listing09.16.CastingBetweenArraysOfEnums.cs new file mode 100644 index 000000000..35735a86b --- /dev/null +++ b/src/Chapter09/Listing09.16.CastingBetweenArraysOfEnums.cs @@ -0,0 +1,30 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_16; + +using System; +#region INCLUDE +enum ConnectionState1 +{ + Disconnected, + Connecting, + Connected, + Disconnecting +} + +enum ConnectionState2 +{ + Disconnected, + Connecting, + Connected, + Disconnecting +} +public class Program +{ + public static void Main() + { + ConnectionState1[] states = + #region HIGHLIGHT + (ConnectionState1[])(Array)new ConnectionState2[42]; + #endregion HIGHLIGHT + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.16.DefiningEnumValuesforFrequentCombinations.cs b/src/Chapter09/Listing09.16.DefiningEnumValuesforFrequentCombinations.cs deleted file mode 100644 index c8419e900..000000000 --- a/src/Chapter09/Listing09.16.DefiningEnumValuesforFrequentCombinations.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_16 -{ - using System; - #region INCLUDE - [Flags] - enum DistributedChannel - { - None = 0, - Transacted = 1, - Queued = 2, - Encrypted = 4, - Persisted = 16, - #region HIGHLIGHT - FaultTolerant = - Transacted | Queued | Persisted - #endregion HIGHLIGHT - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.cs b/src/Chapter09/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.cs new file mode 100644 index 000000000..9a7ab2ade --- /dev/null +++ b/src/Chapter09/Listing09.17.ConvertingAStringToAnEnumUsingEnum.TryParse.cs @@ -0,0 +1,17 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_17; + +using System; + +public class Program +{ + public static void Main() + { + #region INCLUDE + System.Diagnostics.ThreadPriorityLevel priority; + if(Enum.TryParse("Idle", out priority)) + { + Console.WriteLine(priority); + } + #endregion INCLUDE + } +} diff --git a/src/Chapter09/Listing09.17.UsingFlagsAttribute.cs b/src/Chapter09/Listing09.17.UsingFlagsAttribute.cs deleted file mode 100644 index fd26be49f..000000000 --- a/src/Chapter09/Listing09.17.UsingFlagsAttribute.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_17 -{ - #region INCLUDE - //FileAttributes are defined in System.IO - - using System; - using System.IO; - - public class Program - { - public static void Main() - { - string fileName = @"enumtest.txt"; - #region EXCLUDE - // Cleanup in case the file is left in read-only state - // and can't get created. - if (File.Exists(fileName)) - { - FileAttributes attrs = File.GetAttributes(fileName); - if (attrs.HasFlag(FileAttributes.ReadOnly)) - File.SetAttributes(fileName, attrs & ~FileAttributes.ReadOnly); - } - #endregion EXCLUDE - FileInfo file = new FileInfo(fileName); - file.Open(FileMode.OpenOrCreate).Dispose(); - - FileAttributes startingAttributes = - file.Attributes; - - file.Attributes = FileAttributes.Hidden | - FileAttributes.ReadOnly; - - Console.WriteLine("\"{0}\" outputs as \"{1}\"", - file.Attributes.ToString().Replace(",", " |"), - file.Attributes); - - FileAttributes attributes = - (FileAttributes)Enum.Parse(typeof(FileAttributes), - file.Attributes.ToString()); - - Console.WriteLine(attributes); - - File.SetAttributes(fileName, - startingAttributes); - file.Delete(); - } - } - #endregion INCLUDE -} diff --git a/src/Chapter09/Listing09.18.UsingEnumsAsFlags.cs b/src/Chapter09/Listing09.18.UsingEnumsAsFlags.cs new file mode 100644 index 000000000..c2646ceed --- /dev/null +++ b/src/Chapter09/Listing09.18.UsingEnumsAsFlags.cs @@ -0,0 +1,25 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_18; + +using System; + +#region INCLUDE +[Flags] +public enum FileAttributes +{ + None = 0, // 000000000000000 + ReadOnly = 1 << 0, // 000000000000001 + Hidden = 1 << 1, // 000000000000010 + System = 1 << 2, // 000000000000100 + Directory = 1 << 4, // 000000000010000 + Archive = 1 << 5, // 000000000100000 + Device = 1 << 6, // 000000001000000 + Normal = 1 << 7, // 000000010000000 + Temporary = 1 << 8, // 000000100000000 + SparseFile = 1 << 9, // 000001000000000 + ReparsePoint = 1 << 10, // 000010000000000 + Compressed = 1 << 11, // 000100000000000 + Offline = 1 << 12, // 001000000000000 + NotContentIndexed = 1 << 13, // 010000000000000 + Encrypted = 1 << 14, // 100000000000000 +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.19.UsingBitwiseORandANDWithFlagEnums.cs b/src/Chapter09/Listing09.19.UsingBitwiseORandANDWithFlagEnums.cs new file mode 100644 index 000000000..bc144943d --- /dev/null +++ b/src/Chapter09/Listing09.19.UsingBitwiseORandANDWithFlagEnums.cs @@ -0,0 +1,62 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_19; + +#region INCLUDE +using System; +using System.IO; + +public class Program +{ + public static void Main() + { + // ... + + string fileName = @"enumtest.txt"; + + #region EXCLUDE + System.IO.FileInfo enumFile = + new System.IO.FileInfo(fileName); + if (!enumFile.Exists) + { + enumFile.Create().Dispose(); + } + + try + { + #endregion EXCLUDE + System.IO.FileInfo file = + new System.IO.FileInfo(fileName); + + file.Attributes = FileAttributes.Hidden | + FileAttributes.ReadOnly; + + Console.WriteLine($"{file.Attributes} = {(int)file.Attributes}"); + + // Only the ReadOnly attribute works on Linux (The Hidden attribute does not work on Linux) + if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux)) + { + // Added in C# 4.0/Microsoft .NET Framework 4.0 + if (!file.Attributes.HasFlag(FileAttributes.Hidden)) + { + throw new Exception("File is not hidden."); + } + } + + if ((file.Attributes & FileAttributes.ReadOnly) != + FileAttributes.ReadOnly) + { + throw new Exception("File is not read-only."); + } + #region EXCLUDE + } + finally + { + if (enumFile.Exists) + { + enumFile.Attributes = FileAttributes.Normal; + enumFile.Delete(); + } + } + #endregion EXCLUDE + } +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.20.DefiningEnumValuesforFrequentCombinations.cs b/src/Chapter09/Listing09.20.DefiningEnumValuesforFrequentCombinations.cs new file mode 100644 index 000000000..6b9b1bec6 --- /dev/null +++ b/src/Chapter09/Listing09.20.DefiningEnumValuesforFrequentCombinations.cs @@ -0,0 +1,18 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_20; + +using System; +#region INCLUDE +[Flags] +enum DistributedChannel +{ + None = 0, + Transacted = 1, + Queued = 2, + Encrypted = 4, + Persisted = 16, + #region HIGHLIGHT + FaultTolerant = + Transacted | Queued | Persisted + #endregion HIGHLIGHT +} +#endregion INCLUDE diff --git a/src/Chapter09/Listing09.21.UsingFlagsAttribute.cs b/src/Chapter09/Listing09.21.UsingFlagsAttribute.cs new file mode 100644 index 000000000..e6bf384b0 --- /dev/null +++ b/src/Chapter09/Listing09.21.UsingFlagsAttribute.cs @@ -0,0 +1,48 @@ +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09_21; + +#region INCLUDE +//FileAttributes are defined in System.IO + +using System; +using System.IO; + +public class Program +{ + public static void Main() + { + string fileName = @"enumtest.txt"; + #region EXCLUDE + // Cleanup in case the file is left in read-only state + // and can't get created. + if (File.Exists(fileName)) + { + FileAttributes attrs = File.GetAttributes(fileName); + if (attrs.HasFlag(FileAttributes.ReadOnly)) + File.SetAttributes(fileName, attrs & ~FileAttributes.ReadOnly); + } + #endregion EXCLUDE + FileInfo file = new FileInfo(fileName); + file.Open(FileMode.OpenOrCreate).Dispose(); + + FileAttributes startingAttributes = + file.Attributes; + + file.Attributes = FileAttributes.Hidden | + FileAttributes.ReadOnly; + + Console.WriteLine("\"{0}\" outputs as \"{1}\"", + file.Attributes.ToString().Replace(",", " |"), + file.Attributes); + + FileAttributes attributes = + (FileAttributes)Enum.Parse(typeof(FileAttributes), + file.Attributes.ToString()); + + Console.WriteLine(attributes); + + File.SetAttributes(fileName, + startingAttributes); + file.Delete(); + } +} +#endregion INCLUDE diff --git a/src/Chapter10.Tests/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs b/src/Chapter10.Tests/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs similarity index 66% rename from src/Chapter10.Tests/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs rename to src/Chapter10.Tests/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs index 7a3e219a1..8831bf7eb 100644 --- a/src/Chapter10.Tests/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs +++ b/src/Chapter10.Tests/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.Tests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_01.Tests; [TestClass] public class ProductSerialNumberTests @@ -8,8 +8,8 @@ public class ProductSerialNumberTests [TestMethod] public void Equals_GivenEqualObjects_Equal() { - ProductSerialNumber productSerialNumber1 = new ProductSerialNumber("12", 11, 11001); - ProductSerialNumber productSerialNumber2 = new ProductSerialNumber("12", 11, 11001); + ProductSerialNumber productSerialNumber1 = new("12", 11, 11001); + ProductSerialNumber productSerialNumber2 = new("12", 11, 11001); Assert.IsTrue(productSerialNumber1.Equals(productSerialNumber2)); } @@ -21,16 +21,17 @@ public void Equals_GivenEqualObjects_Equal() public void NotEquals_GivenDifferentObjects_NotEqual(string productSeries1, int model1, int id1, string productSeries2 ,int model2, long id2) { - ProductSerialNumber productSerialNumber1 = new ProductSerialNumber(productSeries1, model1, id1); - ProductSerialNumber productSerialNumber2 = new ProductSerialNumber(productSeries2, model2, id2); + ProductSerialNumber productSerialNumber1 = new(productSeries1, model1, id1); + ProductSerialNumber productSerialNumber2 = new(productSeries2, model2, id2); Assert.IsTrue(productSerialNumber1 != productSerialNumber2); } [TestMethod] + [Ignore("Switch to use records")] public void Equals_GivenNull_NotEqual() { - ProductSerialNumber productSerialNumber1 = new ProductSerialNumber("12", 11, 11001); + ProductSerialNumber productSerialNumber1 = new("12", 11, 11001); ProductSerialNumber? productSerialNumber2 = null; @@ -38,18 +39,20 @@ public void Equals_GivenNull_NotEqual() } [TestMethod] + [Ignore("Switch to use records")] public void Equals_GivenSameReference_Equal() { - ProductSerialNumber productSerialNumber1 = new ProductSerialNumber("12", 11, 11001); + ProductSerialNumber productSerialNumber1 = new("12", 11, 11001); ProductSerialNumber productSerialNumber2 = productSerialNumber1; Assert.IsTrue(productSerialNumber1 == productSerialNumber2); } [TestMethod] + [Ignore("Switch to use records")] public void Equals_GivenDifferentTypes_NotEqual() { - ProductSerialNumber productSerialNumber1 = new ProductSerialNumber("12", 11, 11001); + ProductSerialNumber productSerialNumber1 = new("12", 11, 11001); int otherObj = 12; Assert.IsFalse(productSerialNumber1.Equals(otherObj)); diff --git a/src/Chapter10.Tests/Listing10.07.AddingAnOperator.Tests.cs b/src/Chapter10.Tests/Listing10.02.AddingAnOperator.Tests.cs similarity index 75% rename from src/Chapter10.Tests/Listing10.07.AddingAnOperator.Tests.cs rename to src/Chapter10.Tests/Listing10.02.AddingAnOperator.Tests.cs index cd2f24009..d3b535dd9 100644 --- a/src/Chapter10.Tests/Listing10.07.AddingAnOperator.Tests.cs +++ b/src/Chapter10.Tests/Listing10.02.AddingAnOperator.Tests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_07.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_02.Tests; [TestClass] public class CoordinateTests @@ -8,9 +8,9 @@ public class CoordinateTests [TestMethod] public void CoordinateEquals_GivenEqualObjects_AreEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); - Coordinate coordinate2 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate2 = new(new Longitude(48, 52), new Latitude(-2, -20)); Assert.IsTrue(coordinate1.Equals(coordinate2)); @@ -24,9 +24,9 @@ public void CoordinateEquals_GivenEqualObjects_AreEqual() public void CoordinateNotEquals_GivenDifferentObjects_NotEqual(int longDegrees1, int longMinutes1, int latDegrees1, int latMinutes1, int longDegrees2, int longMinutes2, int latDegrees2, int latMinutes2) { - Coordinate coordinate1 = new Coordinate(new Longitude(longDegrees1, longMinutes1), + Coordinate coordinate1 = new(new Longitude(longDegrees1, longMinutes1), new Latitude(latDegrees1, latMinutes1)); - Coordinate coordinate2 = new Coordinate(new Longitude(longDegrees2, longMinutes2), + Coordinate coordinate2 = new(new Longitude(longDegrees2, longMinutes2), new Latitude(latDegrees2, latMinutes2)); Assert.IsTrue(coordinate1 != coordinate2); @@ -35,7 +35,7 @@ public void CoordinateNotEquals_GivenDifferentObjects_NotEqual(int longDegrees1, [TestMethod] public void CoordinateEquals_GivenNull_NotEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); Coordinate? coordinate2 = null; @@ -45,7 +45,7 @@ public void CoordinateEquals_GivenNull_NotEqual() [TestMethod] public void CoordinateEquals_GivenSameReference_Equal() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); Coordinate coordinate2 = coordinate1; @@ -55,7 +55,7 @@ public void CoordinateEquals_GivenSameReference_Equal() [TestMethod] public void CoordinateEquals_GivenDifferentTypes_NotEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); int otherObj = 12; @@ -66,9 +66,9 @@ public void CoordinateEquals_GivenDifferentTypes_NotEqual() [TestMethod] public void CoordinateAdd_GivenArc_CoordinateOffset() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); - Arc arc = new Arc(new Longitude(3), new Latitude(1)); + Arc arc = new(new Longitude(3), new Latitude(1)); coordinate += arc; Assert.AreEqual(51, coordinate.Longitude.Degrees); @@ -80,9 +80,9 @@ public void CoordinateAdd_GivenArc_CoordinateOffset() [TestMethod] public void CoordinateSubtract_GivenArc_CoordinateOffset() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); - Arc arc = new Arc(new Longitude(3), new Latitude(1)); + Arc arc = new(new Longitude(3), new Latitude(1)); coordinate -= arc; Assert.AreEqual(45, coordinate.Longitude.Degrees); @@ -94,7 +94,7 @@ public void CoordinateSubtract_GivenArc_CoordinateOffset() [TestMethod] public void CoordinateToString_ValidateCoordinate() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); string expected = @"48° 52' 0 E -2° -20' 0 N"; diff --git a/src/Chapter10.Tests/Listing10.08.CallingTheMinusAndPlusBinaryOperators.Tests.cs b/src/Chapter10.Tests/Listing10.03.CallingTheMinusAndPlusBinaryOperators.Tests.cs similarity index 96% rename from src/Chapter10.Tests/Listing10.08.CallingTheMinusAndPlusBinaryOperators.Tests.cs rename to src/Chapter10.Tests/Listing10.03.CallingTheMinusAndPlusBinaryOperators.Tests.cs index aabe54702..f92434e52 100644 --- a/src/Chapter10.Tests/Listing10.08.CallingTheMinusAndPlusBinaryOperators.Tests.cs +++ b/src/Chapter10.Tests/Listing10.03.CallingTheMinusAndPlusBinaryOperators.Tests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_08.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_03.Tests; [TestClass] public class ProgramTests diff --git a/src/Chapter10.Tests/Listing10.03.OverridingEqualityOperator.Tests.cs b/src/Chapter10.Tests/Listing10.03.OverridingEqualityOperator.Tests.cs deleted file mode 100644 index 9691af7e6..000000000 --- a/src/Chapter10.Tests/Listing10.03.OverridingEqualityOperator.Tests.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_03.Tests; - -[TestClass] -public class ProgramTests -{ - [TestMethod] - public void Main_GivenSerialNumbers_EqualityOverrideUsed() - { - const string expected = -@"serialNumber1 reference equals serialNumber2 -serialNumber1 equals serialNumber2 -serialNumber1 equals serialNumber3"; - - IntelliTect.TestTools.Console.ConsoleAssert.Expect( - expected, Program.Main); - } -} diff --git a/src/Chapter10.Tests/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs b/src/Chapter10.Tests/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs similarity index 75% rename from src/Chapter10.Tests/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs rename to src/Chapter10.Tests/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs index f4ac70505..dc016af68 100644 --- a/src/Chapter10.Tests/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs +++ b/src/Chapter10.Tests/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.Tests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_09.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_04.Tests; [TestClass] public class ArcTests @@ -8,7 +8,7 @@ public class ArcTests [TestMethod] public void ArcUnaryMinus_InvertSignOfArc() { - Arc arc = new Arc(new Longitude(48), new Latitude(12)); + Arc arc = new(new Longitude(48), new Latitude(12)); arc = -arc; Assert.AreEqual(-48, arc.LongitudeDifference.Degrees); @@ -22,7 +22,7 @@ public class CoordinateTests [TestMethod] public void ArcUnaryPlus_KeepSignOfArc() { - Arc arc = new Arc(new Longitude(48), new Latitude(12)); + Arc arc = new(new Longitude(48), new Latitude(12)); arc = +arc; Assert.AreEqual(48, arc.LongitudeDifference.Degrees); @@ -33,9 +33,9 @@ public void ArcUnaryPlus_KeepSignOfArc() [TestMethod] public void CoordinateEquals_GivenEqualObjects_AreEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); - Coordinate coordinate2 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate2 = new(new Longitude(48, 52), new Latitude(-2, -20)); Assert.IsTrue(coordinate1.Equals(coordinate2)); @@ -49,9 +49,9 @@ public void CoordinateEquals_GivenEqualObjects_AreEqual() public void CoordinateNotEquals_GivenDifferentObjects_NotEqual(int longDegrees1, int longMinutes1, int latDegrees1, int latMinutes1, int longDegrees2, int longMinutes2, int latDegrees2, int latMinutes2) { - Coordinate coordinate1 = new Coordinate(new Longitude(longDegrees1, longMinutes1), + Coordinate coordinate1 = new(new Longitude(longDegrees1, longMinutes1), new Latitude(latDegrees1, latMinutes1)); - Coordinate coordinate2 = new Coordinate(new Longitude(longDegrees2, longMinutes2), + Coordinate coordinate2 = new(new Longitude(longDegrees2, longMinutes2), new Latitude(latDegrees2, latMinutes2)); Assert.IsTrue(coordinate1 != coordinate2); @@ -60,7 +60,7 @@ public void CoordinateNotEquals_GivenDifferentObjects_NotEqual(int longDegrees1, [TestMethod] public void CoordinateEquals_GivenNull_NotEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); Coordinate? coordinate2 = null; @@ -70,7 +70,7 @@ public void CoordinateEquals_GivenNull_NotEqual() [TestMethod] public void CoordinateEquals_GivenSameReference_Equal() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); Coordinate coordinate2 = coordinate1; @@ -80,7 +80,7 @@ public void CoordinateEquals_GivenSameReference_Equal() [TestMethod] public void CoordinateEquals_GivenDifferentTypes_NotEqual() { - Coordinate coordinate1 = new Coordinate(new Longitude(48, 52), + Coordinate coordinate1 = new(new Longitude(48, 52), new Latitude(-2, -20)); int otherObj = 12; @@ -91,9 +91,9 @@ public void CoordinateEquals_GivenDifferentTypes_NotEqual() [TestMethod] public void CoordinateAdd_GivenArc_CoordinateOffset() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); - Arc arc = new Arc(new Longitude(3), new Latitude(1)); + Arc arc = new(new Longitude(3), new Latitude(1)); coordinate += arc; Assert.AreEqual(51, coordinate.Longitude.Degrees); @@ -105,9 +105,9 @@ public void CoordinateAdd_GivenArc_CoordinateOffset() [TestMethod] public void CoordinateSubtract_GivenArc_CoordinateOffset() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); - Arc arc = new Arc(new Longitude(3), new Latitude(1)); + Arc arc = new(new Longitude(3), new Latitude(1)); coordinate -= arc; Assert.AreEqual(45, coordinate.Longitude.Degrees); @@ -119,7 +119,7 @@ public void CoordinateSubtract_GivenArc_CoordinateOffset() [TestMethod] public void CoordinateToString_ValidateCoordinate() { - Coordinate coordinate = new Coordinate(new Longitude(48, 52), + Coordinate coordinate = new(new Longitude(48, 52), new Latitude(-2, -20)); string expected = @"48° 52' 0 E -2° -20' 0 N"; diff --git a/src/Chapter10.Tests/Listing10.04.ValueTypesNeverReferenceEqualThemselves.Tests.cs b/src/Chapter10.Tests/Listing10.04.ValueTypesNeverReferenceEqualThemselves.Tests.cs deleted file mode 100644 index 60f36f3e7..000000000 --- a/src/Chapter10.Tests/Listing10.04.ValueTypesNeverReferenceEqualThemselves.Tests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_04.Tests; - -[TestClass] -public class ProgramTests -{ - [TestMethod] - public void Main_ReferenceEqualsOnValueType_ReferencesNotEqual() - { - const string expected = "coordinate1 does NOT reference equal itself"; - - IntelliTect.TestTools.Console.ConsoleAssert.Expect( - expected, Program.Main); - } -} diff --git a/src/Chapter10.Tests/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs b/src/Chapter10.Tests/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs similarity index 90% rename from src/Chapter10.Tests/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs rename to src/Chapter10.Tests/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs index 64aedee01..772ed7d1d 100644 --- a/src/Chapter10.Tests/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs +++ b/src/Chapter10.Tests/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.Tests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_11.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06.Tests; [TestClass] public class LatitudeTests @@ -8,7 +8,7 @@ public class LatitudeTests [TestMethod] public void LatitudeDoubleCast_GivenValidLatitude_CastDegreesToDouble() { - Latitude latitude = new Latitude(12); + Latitude latitude = new(12); double castTo = (Double) latitude; diff --git a/src/Chapter10.Tests/Listing10.12.Tests.cs b/src/Chapter10.Tests/Listing10.07.LeveragingADifferentLibrary.Tests.cs similarity index 89% rename from src/Chapter10.Tests/Listing10.12.Tests.cs rename to src/Chapter10.Tests/Listing10.07.LeveragingADifferentLibrary.Tests.cs index 2fd6a0fc3..676826c77 100644 --- a/src/Chapter10.Tests/Listing10.12.Tests.cs +++ b/src/Chapter10.Tests/Listing10.07.LeveragingADifferentLibrary.Tests.cs @@ -1,7 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Text.RegularExpressions; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_12.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_07.Tests; [TestClass] public class TextNumberParserTests @@ -18,13 +18,13 @@ This is a test of the emergency... """; - Action act = () => Program.Main(new[] + static void invokeMain() => Program.Main(new[] { "black", "blue", "brown", "CBR", "orange", "purple", "red", "yellow" }); - string? result = Execute(act); + string? result = Execute(invokeMain); Assert.AreEqual(expected, result); } @@ -55,4 +55,4 @@ private static string RemoveVT100(string removeFrom) { return Regex.Replace(removeFrom, "\u001b\\[\\d{1,3}m", ""); } -} \ No newline at end of file +} diff --git a/src/Chapter10.Tests/Listing10.13.MakingTypesAvailableOutsideAnAssembly.Tests.cs b/src/Chapter10.Tests/Listing10.08.MakingTypesAvailableExternally.Tests.cs similarity index 77% rename from src/Chapter10.Tests/Listing10.13.MakingTypesAvailableOutsideAnAssembly.Tests.cs rename to src/Chapter10.Tests/Listing10.08.MakingTypesAvailableExternally.Tests.cs index 1f97fba15..879a3d0f0 100644 --- a/src/Chapter10.Tests/Listing10.13.MakingTypesAvailableOutsideAnAssembly.Tests.cs +++ b/src/Chapter10.Tests/Listing10.08.MakingTypesAvailableExternally.Tests.cs @@ -1,7 +1,7 @@ -using AddisonWesley.Michaelis.EssentialCSharp.Shared.Tests; +using AddisonWesley.Michaelis.EssentialCSharp.Shared.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_13.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_08.Tests; [TestClass] public class TypeTests @@ -10,9 +10,9 @@ public class TypeTests [TestMethod] public void MakingTypesAvailableExternallyPS1_ExitCodeIs0() { - if (PowerShellTestUtilities.PowerShellNotInstalled) Assert.Inconclusive("Powershell not installed"); + if (PowerShellTestUtilities.PowerShellNotInstalled) Assert.Inconclusive("PowerShell not installed"); //EssentialCSharp\\src\\Chapter10.Tests\\bin\\Debug\\netcoreapp3.0 - string ps1Path = Path.GetFullPath("../../../../Chapter10/Listing10.13.MakingTypesAvailableExternally.ps1", Environment.CurrentDirectory); + string ps1Path = Path.GetFullPath("../../../../Chapter10/Listing10.08.MakingTypesAvailableExternally.ps1", Environment.CurrentDirectory); string traceValue = "0"; int exitCode = PowerShellTestUtilities.RunPowerShellScript(ps1Path, traceValue); diff --git a/src/Chapter10.Tests/Listing10.20.Tests.cs b/src/Chapter10.Tests/Listing10.14.DefiningAFinalizer.Tests.cs similarity index 94% rename from src/Chapter10.Tests/Listing10.20.Tests.cs rename to src/Chapter10.Tests/Listing10.14.DefiningAFinalizer.Tests.cs index b0715577d..6eff787a4 100644 --- a/src/Chapter10.Tests/Listing10.20.Tests.cs +++ b/src/Chapter10.Tests/Listing10.14.DefiningAFinalizer.Tests.cs @@ -1,7 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Runtime.InteropServices; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_20.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_14.Tests; [TestClass] public class TemporaryFileStreamTests @@ -44,7 +44,7 @@ private static void DeleteTempFile() [TestMethod] public void Create_GivenNewDocument_FileGetsCreated() { - TemporaryFileStream fileStream = new TemporaryFileStream(TempFileName); + TemporaryFileStream fileStream = new(TempFileName); Assert.IsTrue(File.Exists(fileStream.File?.FullName!)); } @@ -93,4 +93,4 @@ static bool IsFileLocked(FileInfo file) } } } -} \ No newline at end of file +} diff --git a/src/Chapter10.Tests/Listing10.21.Tests.cs b/src/Chapter10.Tests/Listing10.15.ResourceCleanupWithIDisposable.Tests.cs similarity index 80% rename from src/Chapter10.Tests/Listing10.21.Tests.cs rename to src/Chapter10.Tests/Listing10.15.ResourceCleanupWithIDisposable.Tests.cs index 78dfedab5..708db3330 100644 --- a/src/Chapter10.Tests/Listing10.21.Tests.cs +++ b/src/Chapter10.Tests/Listing10.15.ResourceCleanupWithIDisposable.Tests.cs @@ -1,6 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_15.Tests; [TestClass] public class SearchTests @@ -13,4 +13,4 @@ public void MainTest() IntelliTect.TestTools.Console.ConsoleAssert.Expect( expected, Program.Search); } -} \ No newline at end of file +} diff --git a/src/Chapter10.Tests/Listing10.23.RegisteringAFinalizerWithProcessExit.Tests.cs b/src/Chapter10.Tests/Listing10.17.RegisteringAFinalizerWithProcessExit.Tests.cs similarity index 93% rename from src/Chapter10.Tests/Listing10.23.RegisteringAFinalizerWithProcessExit.Tests.cs rename to src/Chapter10.Tests/Listing10.17.RegisteringAFinalizerWithProcessExit.Tests.cs index 973c98371..02f3f692e 100644 --- a/src/Chapter10.Tests/Listing10.23.RegisteringAFinalizerWithProcessExit.Tests.cs +++ b/src/Chapter10.Tests/Listing10.17.RegisteringAFinalizerWithProcessExit.Tests.cs @@ -3,7 +3,7 @@ using System.Text.RegularExpressions; -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_23.Tests; +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_17.Tests; [TestClass] public class DisposeTests @@ -15,14 +15,14 @@ public class DisposeTests Path.Join(IntelliTect.Multitool.RepositoryPaths.GetDefaultRepoRoot(),"src", "Chapter10")); static string Ps1Path { get; } = - Path.GetFullPath(Path.Join(Ps1DirectoryPath, "Listing10.23.RegisteringAFinalizerWithProcessExit.ps1"), Environment.CurrentDirectory); + Path.GetFullPath(Path.Join(Ps1DirectoryPath, "Listing10.17.RegisteringAFinalizerWithProcessExit.ps1"), Environment.CurrentDirectory); private const string ProjectName = "ProcessExitTestProgram.testing"; [ClassInitialize] - public static void ClassInitialize(TestContext testContext) + public static void ClassInitialize(TestContext _) { - // Clean up at the start incase the class cleanup doesn't run (due to debug for example) + // Clean up at the start in case the class cleanup doesn't run (due to debug for example) Assert.AreEqual(0, RunPowerShellScript("cleanup", out string _)); string testStage = "create"; Assert.AreEqual(0, RunPowerShellScript(testStage, out string psOutput), @@ -50,9 +50,8 @@ public void FinalizerRunsAsPredicted_ConsoleOutputIsInOrder(string finalizerOrde string testStatus = "run"; TestContext.WriteLine($"Ps1Path = '{Path.GetFullPath(Ps1Path)}'"); - string psOutput; int exitCode = RunPowerShellScript( - testStatus, finalizerOrderOption, traceValue, out psOutput); + testStatus, finalizerOrderOption, traceValue, out string psOutput); Assert.AreEqual(0, exitCode, $"PowerShell Output: {psOutput}"); diff --git a/src/Chapter10/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.cs b/src/Chapter10/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.cs similarity index 97% rename from src/Chapter10/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.cs rename to src/Chapter10/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.cs index 82e80bf26..5df0b144e 100644 --- a/src/Chapter10/Listing10.06.ImplementingTheEqualsAndNotEqualsOperators.cs +++ b/src/Chapter10/Listing10.01.ImplementingTheEqualsAndNotEqualsOperators.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_01 { #region INCLUDE public sealed class ProductSerialNumber diff --git a/src/Chapter10/Listing10.01.OverridingToString.cs b/src/Chapter10/Listing10.01.OverridingToString.cs deleted file mode 100644 index 21ebf94c5..000000000 --- a/src/Chapter10/Listing10.01.OverridingToString.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_01 -{ - #region INCLUDE - public struct Coordinate - { - public Coordinate(Longitude longitude, Latitude latitude) - { - Longitude = longitude; - Latitude = latitude; - } - - public Longitude Longitude { get; } - public Latitude Latitude { get; } - - #region HIGHLIGHT - public override string ToString() => - $"{ Longitude } { Latitude }"; - #endregion HIGHLIGHT - - // ... - } - #endregion INCLUDE - - public struct Longitude { } - public struct Latitude { } -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.07.AddingAnOperator.cs b/src/Chapter10/Listing10.02.AddingAnOperator.cs similarity index 95% rename from src/Chapter10/Listing10.07.AddingAnOperator.cs rename to src/Chapter10/Listing10.02.AddingAnOperator.cs index 8b746ae85..ca7127596 100644 --- a/src/Chapter10/Listing10.07.AddingAnOperator.cs +++ b/src/Chapter10/Listing10.02.AddingAnOperator.cs @@ -1,7 +1,7 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_07 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_02 { #region INCLUDE - public struct Arc + public readonly struct Arc { public Arc( Longitude longitudeDifference, @@ -16,7 +16,7 @@ public Arc( } - public struct Coordinate + public readonly struct Coordinate { #region EXCLUDE public Coordinate(Longitude longitude, Latitude latitude) @@ -28,7 +28,7 @@ public Coordinate(Longitude longitude, Latitude latitude) public static Coordinate operator +( Coordinate source, Arc arc) { - Coordinate result = new Coordinate( + Coordinate result = new( new Longitude( source.Longitude + arc.LongitudeDifference), new Latitude( @@ -40,7 +40,7 @@ public Coordinate(Longitude longitude, Latitude latitude) public static Coordinate operator -( Coordinate source, Arc arc) { - Coordinate result = new Coordinate( + Coordinate result = new( new Longitude( source.Longitude - arc.LongitudeDifference), new Latitude( @@ -138,7 +138,7 @@ public override string ToString() } #endregion INCLUDE - public struct Longitude + public readonly struct Longitude { public Longitude(int degrees, int minutes) { @@ -167,7 +167,7 @@ public Longitude(Longitude longitude) } } - public struct Latitude + public readonly struct Latitude { public Latitude(int degrees, int minutes) { @@ -195,4 +195,4 @@ public Latitude(Latitude Latitude) return new Latitude(leftHandSide.Degrees - rightHandSide.Degrees, leftHandSide.Minutes - rightHandSide.Minutes); } } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.02.ImplementingGetHashCode.cs b/src/Chapter10/Listing10.02.ImplementingGetHashCode.cs deleted file mode 100644 index 139d6225d..000000000 --- a/src/Chapter10/Listing10.02.ImplementingGetHashCode.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_02 -{ - #region INCLUDE - public struct Coordinate - { - public Coordinate(Longitude longitude, Latitude latitude) - { - Longitude = longitude; - Latitude = latitude; - } - - public Longitude Longitude { get; } - public Latitude Latitude { get; } - - #region HIGHLIGHT - public override int GetHashCode() => - HashCode.Combine( - Longitude.GetHashCode(), Latitude.GetHashCode()); - #endregion HIGHLIGHT - - #region EXCLUDE - public override string ToString() => - $"{ Longitude } { Latitude }"; - #endregion EXCLUDE - } - #endregion INCLUDE - - public struct Longitude { } - public struct Latitude { } -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.08.CallingTheMinusAndPlusBinaryOperators.cs b/src/Chapter10/Listing10.03.CallingTheMinusAndPlusBinaryOperators.cs similarity index 67% rename from src/Chapter10/Listing10.08.CallingTheMinusAndPlusBinaryOperators.cs rename to src/Chapter10/Listing10.03.CallingTheMinusAndPlusBinaryOperators.cs index 5251d5b39..e9f380711 100644 --- a/src/Chapter10/Listing10.08.CallingTheMinusAndPlusBinaryOperators.cs +++ b/src/Chapter10/Listing10.03.CallingTheMinusAndPlusBinaryOperators.cs @@ -1,8 +1,10 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_08 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_03 { using System; - using Listing10_07; + using Listing10_02; #region INCLUDE + // Use compound assignment suppressed for demonstration purposes + #pragma warning disable IDE0054 public class Program { public static void Main() @@ -10,7 +12,7 @@ public static void Main() Coordinate coordinate1, coordinate2; coordinate1 = new Coordinate( new Longitude(48, 52), new Latitude(-2, -20)); - Arc arc = new Arc(new Longitude(3), new Latitude(1)); + Arc arc = new(new Longitude(3), new Latitude(1)); coordinate2 = coordinate1 + arc; Console.WriteLine(coordinate2); @@ -23,4 +25,4 @@ public static void Main() } } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.03.OverridingEqualityOperator.cs b/src/Chapter10/Listing10.03.OverridingEqualityOperator.cs deleted file mode 100644 index 4cd5479e3..000000000 --- a/src/Chapter10/Listing10.03.OverridingEqualityOperator.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_03 -{ - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06; - #region INCLUDE - // This ProductSerialNumber class is shown and implemented in 10.6 - // public sealed class ProductSerialNumber - // { - // } - - public class Program - { - public static void Main() - { - ProductSerialNumber serialNumber1 = - new ProductSerialNumber("PV", 1000, 09187234); - ProductSerialNumber serialNumber2 = serialNumber1; - ProductSerialNumber serialNumber3 = - new ProductSerialNumber("PV", 1000, 09187234); - - // These serial numbers ARE the same object identity - if(!object.ReferenceEquals(serialNumber1, - serialNumber2)) - { - throw new Exception( - "serialNumber1 does NOT " + - "reference equal serialNumber2"); - } - // And, therefore, they are equal - else if(!serialNumber1.Equals(serialNumber2)) - { - throw new Exception( - "serialNumber1 does NOT equal serialNumber2"); - } - else - { - Console.WriteLine( - "serialNumber1 reference equals serialNumber2"); - Console.WriteLine( - "serialNumber1 equals serialNumber2"); - } - - - // These serial numbers are NOT the same object identity - if(object.ReferenceEquals(serialNumber1, - serialNumber3)) - { - throw new Exception( - "serialNumber1 DOES reference " + - "equal serialNumber3"); - } - // But they are equal (assuming Equals is overloaded) - else if(!serialNumber1.Equals(serialNumber3) || - serialNumber1 != serialNumber3) - { - throw new Exception( - "serialNumber1 does NOT equal serialNumber3"); - } - - Console.WriteLine("serialNumber1 equals serialNumber3"); - } - } - #endregion INCLUDE -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.cs b/src/Chapter10/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.cs similarity index 97% rename from src/Chapter10/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.cs rename to src/Chapter10/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.cs index 5456569be..cfa6fb51a 100644 --- a/src/Chapter10/Listing10.09.OverloadingTheMinusAndPlusUnaryOperators.cs +++ b/src/Chapter10/Listing10.04.OverloadingTheMinusAndPlusUnaryOperators.cs @@ -1,6 +1,6 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_09 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_04 { - public struct Coordinate + public readonly struct Coordinate { public Coordinate(Longitude longitude, Latitude latitude) { @@ -11,7 +11,7 @@ public Coordinate(Longitude longitude, Latitude latitude) public static Coordinate operator +( Coordinate source, Arc arc) { - Coordinate result = new Coordinate( + Coordinate result = new( new Longitude( source.Longitude + arc.LongitudeDifference), new Latitude( @@ -22,7 +22,7 @@ public Coordinate(Longitude longitude, Latitude latitude) public static Coordinate operator -( Coordinate source, Arc arc) { - Coordinate result = new Coordinate( + Coordinate result = new( new Longitude( source.Longitude - arc.LongitudeDifference), new Latitude( @@ -233,7 +233,7 @@ public int Minutes } #endregion EXCLUDE } - public struct Arc + public readonly struct Arc { #region EXCLUDE public Arc( @@ -278,4 +278,4 @@ public Latitude LatitudeDifference } } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.04.ValueTypesNeverReferenceEqualThemselves.cs b/src/Chapter10/Listing10.04.ValueTypesNeverReferenceEqualThemselves.cs deleted file mode 100644 index 8a169124c..000000000 --- a/src/Chapter10/Listing10.04.ValueTypesNeverReferenceEqualThemselves.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Justification: Listing is incomplete for purposes of elucidation. -#pragma warning disable IDE0060 // Remove unused parameter -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_04 -{ - using System; - #region INCLUDE - public struct Coordinate - { - public Coordinate(Longitude longitude, Latitude latitude) - { - Longitude = longitude; - Latitude = latitude; - } - - public Longitude Longitude { get; } - public Latitude Latitude { get; } - // ... - } - - public class Program - { - public static void Main() - { - //... - - Coordinate coordinate1 = - new Coordinate(new Longitude(48, 52), - new Latitude(-2, -20)); - - // Value types will never be reference equal. - if(Coordinate.ReferenceEquals(coordinate1, - coordinate1)) - { - throw new Exception( - "coordinate1 reference equals coordinate1"); - } - - Console.WriteLine( - "coordinate1 does NOT reference equal itself"); - } - } - #endregion INCLUDE - public struct Longitude - { - public Longitude(int x, int y) { } - } - public struct Latitude - { - public Latitude(int x, int y) { } - } -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.05.OverridingEquals.cs b/src/Chapter10/Listing10.05.OverridingEquals.cs deleted file mode 100644 index b823c5307..000000000 --- a/src/Chapter10/Listing10.05.OverridingEquals.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Justification: Listing is incomplete for purposes of elucidation. -#pragma warning disable IDE0060 // Remove unused parameter -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_05 -{ - using System; - - public class Program - { - public static void Main() - { - //... - - Coordinate coordinate1 = - new Coordinate(new Longitude(48, 52), - new Latitude(-2, -20)); - } - } - - #region INCLUDE - public struct Longitude - { - #region EXCLUDE - public Longitude(int x, int y) { } - #endregion EXCLUDE - } - - public struct Latitude - { - #region EXCLUDE - public Latitude(int x, int y) { } - #endregion EXCLUDE - } - - public struct Coordinate : IEquatable - { - public Coordinate(Longitude longitude, Latitude latitude) - { - Longitude = longitude; - Latitude = latitude; - } - - public Longitude Longitude { get; } - public Latitude Latitude { get; } - - public override bool Equals(object? obj) - { - // STEP 1: Check for null - if (obj is null) - { - return false; - } - // STEP 2: Equivalent data types - // can be avoided if type is sealed - if (this.GetType() != obj.GetType()) - { - return false; - } - - // STEP 3: Invoked strongly type helper version of Equals() - return Equals((Coordinate)obj); - } - - public bool Equals(Coordinate obj) - { - // STEP 1: Check for null if a reference type - // (e.g., a reference type) - // if (obj is null) - // { - // return false; - // } - - // STEP 4: Possibly check for equivalent hash codes - // but not if the identity properties are mutable - // and the hash code is cached. - // if (GetHashCode() != obj.GetHashCode()) - // { - // return false; - // } - - // STEP 5: Check base.Equals if base overrides Equals(). - if (!base.Equals(obj)) - { - return false; - } - - // STEP 6: Compare identifying fields for equality - // using an overload of Equals on Longitude - return ((Longitude.Equals(obj.Longitude)) && - (Latitude.Equals(obj.Latitude))); - } - - // STEP 7: Override GetHashCode - public override int GetHashCode() => - #region EXCLUDE - HashCode.Combine(Longitude.GetHashCode(), Latitude.GetHashCode()); - - // STEP 8: Override the ==/!= operators - public static bool operator ==( - Coordinate leftHandSide, - Coordinate rightHandSide) - { - return (leftHandSide.Equals(rightHandSide)); - } - - // STEP 8: Override the ==/!= operators - public static bool operator !=( - Coordinate leftHandSide, - Coordinate rightHandSide) - { - return !(leftHandSide.Equals(rightHandSide)); - } - #endregion EXCLUDE - } - #endregion INCLUDE -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.10.TrueAndFalseOperators.cs b/src/Chapter10/Listing10.05.TrueAndFalseOperators.cs similarity index 84% rename from src/Chapter10/Listing10.10.TrueAndFalseOperators.cs rename to src/Chapter10/Listing10.05.TrueAndFalseOperators.cs index 0d21509b9..f2d99670b 100644 --- a/src/Chapter10/Listing10.10.TrueAndFalseOperators.cs +++ b/src/Chapter10/Listing10.05.TrueAndFalseOperators.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_10 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_05 { public struct Example { @@ -19,4 +19,4 @@ public static bool operator true(object item) #endregion INCLUDE */ } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs b/src/Chapter10/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs similarity index 86% rename from src/Chapter10/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs rename to src/Chapter10/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs index 6d6ac19e4..6702860ac 100644 --- a/src/Chapter10/Listing10.11.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs +++ b/src/Chapter10/Listing10.06.ProvidingAnImplicitConversionBetweenLatitudeAndDouble.cs @@ -1,7 +1,7 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_11 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06 { #region INCLUDE - public struct Latitude + public readonly struct Latitude { // ... @@ -32,4 +32,4 @@ private static double Normalize(double decimalDegrees) #endregion EXCLUDE } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.12.LeveragingADifferentLibrary.cs b/src/Chapter10/Listing10.07.LeveragingADifferentLibrary.cs similarity index 89% rename from src/Chapter10/Listing10.12.LeveragingADifferentLibrary.cs rename to src/Chapter10/Listing10.07.LeveragingADifferentLibrary.cs index 45901d9f5..839c1d99d 100644 --- a/src/Chapter10/Listing10.12.LeveragingADifferentLibrary.cs +++ b/src/Chapter10/Listing10.07.LeveragingADifferentLibrary.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_12 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_07 { using Microsoft.Extensions.Logging; @@ -22,4 +22,4 @@ public static void Main(string[] args) } } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.13.MakingTypesAvailableExternally.cs b/src/Chapter10/Listing10.08.MakingTypesAvailableExternally.cs similarity index 77% rename from src/Chapter10/Listing10.13.MakingTypesAvailableExternally.cs rename to src/Chapter10/Listing10.08.MakingTypesAvailableExternally.cs index fefda2a44..7359568dc 100644 --- a/src/Chapter10/Listing10.13.MakingTypesAvailableExternally.cs +++ b/src/Chapter10/Listing10.08.MakingTypesAvailableExternally.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_13 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_08 { #region INCLUDE public struct Coordinate @@ -21,4 +21,4 @@ public struct Arc // ... } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.13.MakingTypesAvailableExternally.ps1 b/src/Chapter10/Listing10.08.MakingTypesAvailableExternally.ps1 similarity index 100% rename from src/Chapter10/Listing10.13.MakingTypesAvailableExternally.ps1 rename to src/Chapter10/Listing10.08.MakingTypesAvailableExternally.ps1 diff --git a/src/Chapter10/Listing10.14.DefiningANamespace.cs b/src/Chapter10/Listing10.09.DefiningANamespace.cs similarity index 81% rename from src/Chapter10/Listing10.14.DefiningANamespace.cs rename to src/Chapter10/Listing10.09.DefiningANamespace.cs index 6ab3cc29e..14e354a28 100644 --- a/src/Chapter10/Listing10.14.DefiningANamespace.cs +++ b/src/Chapter10/Listing10.09.DefiningANamespace.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_14 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_09 { #region INCLUDE // Define the namespace AddisonWesley @@ -15,4 +15,4 @@ class Program #endregion HIGHLIGHT // End of AddisonWesley namespace declaration #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.15.NestedNamespaces.cs b/src/Chapter10/Listing10.10.NestedNamespaces.cs similarity index 98% rename from src/Chapter10/Listing10.15.NestedNamespaces.cs rename to src/Chapter10/Listing10.10.NestedNamespaces.cs index ff46cabdd..ded756a70 100644 --- a/src/Chapter10/Listing10.15.NestedNamespaces.cs +++ b/src/Chapter10/Listing10.10.NestedNamespaces.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_15 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_10 { #region INCLUDE // Define the namespace AddisonWesley diff --git a/src/Chapter10/Listing10.16.NestingNamespacesWithPeriod.cs b/src/Chapter10/Listing10.11.NestingNamespacesWithPeriod.cs similarity index 83% rename from src/Chapter10/Listing10.16.NestingNamespacesWithPeriod.cs rename to src/Chapter10/Listing10.11.NestingNamespacesWithPeriod.cs index 0939f8a3b..098336aa2 100644 --- a/src/Chapter10/Listing10.16.NestingNamespacesWithPeriod.cs +++ b/src/Chapter10/Listing10.11.NestingNamespacesWithPeriod.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_16 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_11 { #region INCLUDE // Define the namespace AddisonWesley.Michaelis.EssentialCSharp @@ -15,4 +15,4 @@ class Program #endregion HIGHLIGHT // End of AddisonWesley namespace declaration #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.12.CommentingWithXML.cs b/src/Chapter10/Listing10.12.CommentingWithXML.cs new file mode 100644 index 000000000..0fefc6fa3 --- /dev/null +++ b/src/Chapter10/Listing10.12.CommentingWithXML.cs @@ -0,0 +1,59 @@ +// Remove unused parameter disabled for elucidation. +#pragma warning disable IDE0060 +using Chapter10; + +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_12; + +#region INCLUDE +/// +/// DataStorage is used to persist and retrieve +/// employee data from the files. +/// +class DataStorage +{ + /// + /// Save an employee object to a file + /// named with the Employee name. + /// + /// + /// This method uses + /// in addition to + /// + /// + /// + /// The employee to persist to a file + /// January 1, 2000 + public static void Store(Employee employee) + { + // ... + } + + /** + * Loads up an employee object. + * + * + * This method uses + * in addition to + * + * + * + * The first name of the employee + * + * The last name of the employee + * + * The employee object corresponding to the names + * + * January 1, 2000 **/ + public static Employee Load(string firstName, string lastName) + { + #region EXCLUDE + return new Employee(); + #endregion EXCLUDE + } +} + +class Program +{ + // ... +} +#endregion INCLUDE diff --git a/src/Chapter10/Listing10.19.WeakReferences.cs b/src/Chapter10/Listing10.13.WeakReferences.cs similarity index 94% rename from src/Chapter10/Listing10.19.WeakReferences.cs rename to src/Chapter10/Listing10.13.WeakReferences.cs index dca3ba63b..cb0fe0f08 100644 --- a/src/Chapter10/Listing10.19.WeakReferences.cs +++ b/src/Chapter10/Listing10.13.WeakReferences.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_19 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_13 { using System; @@ -77,7 +77,7 @@ static public byte[] GetData() public class ObjectDataSource { - private readonly WeakReference Data = new WeakReference(null); + private readonly WeakReference Data = new(null); public void ClearReference() { Data.Target = null; @@ -107,4 +107,4 @@ public byte[] GetData() } } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.14.DefiningAFinalizer.cs b/src/Chapter10/Listing10.14.DefiningAFinalizer.cs new file mode 100644 index 000000000..5c6290390 --- /dev/null +++ b/src/Chapter10/Listing10.14.DefiningAFinalizer.cs @@ -0,0 +1,57 @@ +// Justification: Implementation is incomplete in the catch block. +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_14; + +using System; +#region INCLUDE +using System.IO; + +public class TemporaryFileStream +{ + public TemporaryFileStream(string fileName) + { + File = new FileInfo(fileName); + // For a preferable solution use FileOptions.DeleteOnClose. + Stream = new FileStream( + File.FullName, FileMode.OpenOrCreate, + FileAccess.ReadWrite); + } + + public TemporaryFileStream() + : this(Path.GetTempFileName()) + { } + + #region HIGHLIGHT + // Finalizer + ~TemporaryFileStream() + { + try + { + Close(); + } + catch (Exception ) + { + // Write event to logs or UI + // ... + } + } + #endregion HIGHLIGHT + + public FileStream? Stream { get; private set; } + public FileInfo? File { get; private set; } + + public void Close() + { + Stream?.Dispose(); + try + { + File?.Delete(); + } + catch(IOException exception) + { + Console.WriteLine(exception); + } + Stream = null; + File = null; + } +} +#endregion INCLUDE diff --git a/src/Chapter10/Listing10.21.ResourceCleanupWithIDisposable.cs b/src/Chapter10/Listing10.15.ResourceCleanupWithIDisposable.cs similarity index 94% rename from src/Chapter10/Listing10.21.ResourceCleanupWithIDisposable.cs rename to src/Chapter10/Listing10.15.ResourceCleanupWithIDisposable.cs index 4789777cd..6765e00fb 100644 --- a/src/Chapter10/Listing10.21.ResourceCleanupWithIDisposable.cs +++ b/src/Chapter10/Listing10.15.ResourceCleanupWithIDisposable.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_15 { #region INCLUDE using System; @@ -10,7 +10,7 @@ public static class Program public static void Search() { TemporaryFileStream fileStream = - new TemporaryFileStream(); + new(); // Use temporary file stream // ... @@ -87,4 +87,4 @@ public void Dispose(bool disposing) } } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.22.InvokingTheUsingStatement.cs b/src/Chapter10/Listing10.16.InvokingTheUsingStatement.cs similarity index 68% rename from src/Chapter10/Listing10.22.InvokingTheUsingStatement.cs rename to src/Chapter10/Listing10.16.InvokingTheUsingStatement.cs index 12509c4a0..51954b5f8 100644 --- a/src/Chapter10/Listing10.22.InvokingTheUsingStatement.cs +++ b/src/Chapter10/Listing10.16.InvokingTheUsingStatement.cs @@ -1,9 +1,9 @@ -// Justification: Use to demonstrate pre-C# 8.0 syntax. +// Justification: Use to demonstrate pre-C# 8.0 syntax. #pragma warning disable IDE0063 // Use simple 'using' statement -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_22 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_16 { - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21; + using Listing10_15; #region INCLUDE public static class Program @@ -13,14 +13,14 @@ public static void Search() #region HIGHLIGHT // C# 8.0 using TemporaryFileStream fileStream1 = - new TemporaryFileStream(); + new(); #endregion HIGHLIGHT #region HIGHLIGHT // Prior to C# 8.0 using (TemporaryFileStream fileStream2 = - new TemporaryFileStream(), - fileStream3 = new TemporaryFileStream()) + new(), + fileStream3 = new()) #endregion HIGHLIGHT { // Use temporary file stream; @@ -28,4 +28,4 @@ public static void Search() } } #endregion INCLUDE -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.17.CommentingWithXML.cs b/src/Chapter10/Listing10.17.CommentingWithXML.cs deleted file mode 100644 index d8417c58a..000000000 --- a/src/Chapter10/Listing10.17.CommentingWithXML.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Chapter10; - -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_17 -{ - #region INCLUDE - /// - /// DataStorage is used to persist and retrieve - /// employee data from the files. - /// - class DataStorage - { - /// - /// Save an employee object to a file - /// named with the Employee name. - /// - /// - /// This method uses - /// in addition to - /// - /// - /// - /// The employee to persist to a file - /// January 1, 2000 - public static void Store(Employee employee) - { - // ... - } - - /** - * Loads up an employee object. - * - * - * This method uses - * in addition to - * - * - * - * The first name of the employee - * - * The last name of the employee - * - * The employee object corresponding to the names - * - * January 1, 2000 **/ - public static Employee Load(string firstName, string lastName) - { - #region EXCLUDE - return new Employee(); - #endregion EXCLUDE - } - } - - class Program - { - // ... - } - #endregion INCLUDE -} \ No newline at end of file diff --git a/src/Chapter10/Listing10.23.RegisteringAFinalizerWithProcessExit.cs b/src/Chapter10/Listing10.17.RegisteringAFinalizerWithProcessExit.cs similarity index 98% rename from src/Chapter10/Listing10.23.RegisteringAFinalizerWithProcessExit.cs rename to src/Chapter10/Listing10.17.RegisteringAFinalizerWithProcessExit.cs index dc03dad78..0b2b70791 100644 --- a/src/Chapter10/Listing10.23.RegisteringAFinalizerWithProcessExit.cs +++ b/src/Chapter10/Listing10.17.RegisteringAFinalizerWithProcessExit.cs @@ -1,4 +1,4 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_23 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_17 { using System; #region INCLUDE @@ -63,7 +63,7 @@ public SampleUnmanagedResource(string fileName) $"{nameof(SampleUnmanagedResource)}.ctor"); WeakReference weakReferenceToSelf = - new WeakReference(this); + new(this); ProcessExitHandler = (_, __) => { WriteLine("Starting...", "ProcessExitHandler"); @@ -132,4 +132,4 @@ public static class ConsoleLogger public static void WriteLine(string? message = null, [CallerMemberName] string? name = null) => Console.WriteLine($"{$"{name}: " }{ message ?? ": Executing" }"); } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.23.RegisteringAFinalizerWithProcessExit.ps1 b/src/Chapter10/Listing10.17.RegisteringAFinalizerWithProcessExit.ps1 similarity index 100% rename from src/Chapter10/Listing10.23.RegisteringAFinalizerWithProcessExit.ps1 rename to src/Chapter10/Listing10.17.RegisteringAFinalizerWithProcessExit.ps1 diff --git a/src/Chapter10/Listing10.24.LazyLoadingAProperty.cs b/src/Chapter10/Listing10.18.LazyLoadingAProperty.cs similarity index 54% rename from src/Chapter10/Listing10.24.LazyLoadingAProperty.cs rename to src/Chapter10/Listing10.18.LazyLoadingAProperty.cs index 7581cd7d4..35fdfb2cc 100644 --- a/src/Chapter10/Listing10.24.LazyLoadingAProperty.cs +++ b/src/Chapter10/Listing10.18.LazyLoadingAProperty.cs @@ -1,14 +1,14 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_24 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_18 { - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21; + using Listing10_15; #region INCLUDE class DataCache { // ... public TemporaryFileStream FileStream => - InternalFileStream??(InternalFileStream = - new TemporaryFileStream()); + InternalFileStream ??= + new TemporaryFileStream(); private TemporaryFileStream? InternalFileStream { get; set; } = null; @@ -19,9 +19,9 @@ private TemporaryFileStream? InternalFileStream #endregion INCLUDE } -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_23_PreCSharp6 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_18_PRECSHARP6 { - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21; + using Listing10_15; class DataCache { @@ -31,10 +31,7 @@ public TemporaryFileStream FileStream { get { - if (_FileStream is null) - { - _FileStream = new TemporaryFileStream(); - } + _FileStream ??= new TemporaryFileStream(); return _FileStream; } } @@ -42,4 +39,4 @@ public TemporaryFileStream FileStream // ... } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.25.UsingSystem.Lazy.cs b/src/Chapter10/Listing10.19.UsingSystem.Lazy.cs similarity index 73% rename from src/Chapter10/Listing10.25.UsingSystem.Lazy.cs rename to src/Chapter10/Listing10.19.UsingSystem.Lazy.cs index fa91a5bc9..d88f76c55 100644 --- a/src/Chapter10/Listing10.25.UsingSystem.Lazy.cs +++ b/src/Chapter10/Listing10.19.UsingSystem.Lazy.cs @@ -1,6 +1,6 @@ -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_25 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_19 { - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21; + using Listing10_15; using System; #region INCLUDE class DataCache @@ -18,9 +18,9 @@ class DataCache #endregion INCLUDE } -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_24_PreCSharp6 +namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_19_Listing10_18_PRECSHARP6 { - using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21; + using Listing10_15; using System; class DataCache @@ -40,8 +40,8 @@ public TemporaryFileStream FileStream return _FileStream.Value; } } - private Lazy _FileStream; + private readonly Lazy _FileStream; // ... } -} \ No newline at end of file +} diff --git a/src/Chapter10/Listing10.20.DefiningAFinalizer.cs b/src/Chapter10/Listing10.20.DefiningAFinalizer.cs deleted file mode 100644 index 8dbc060ce..000000000 --- a/src/Chapter10/Listing10.20.DefiningAFinalizer.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Justification: Implementation is incomplete in the catch block. -#pragma warning disable CS0168 // Variable is declared but never used -namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_20 -{ - using System; - #region INCLUDE - using System.IO; - - public class TemporaryFileStream - { - public TemporaryFileStream(string fileName) - { - File = new FileInfo(fileName); - // For a preferable solution use FileOptions.DeleteOnClose. - Stream = new FileStream( - File.FullName, FileMode.OpenOrCreate, - FileAccess.ReadWrite); - } - - public TemporaryFileStream() - : this(Path.GetTempFileName()) - { } - - #region HIGHLIGHT - // Finalizer - ~TemporaryFileStream() - { - try - { - Close(); - } - catch (Exception exception) - { - // Write event to logs or UI - // ... - } - } - #endregion HIGHLIGHT - - public FileStream? Stream { get; private set; } - public FileInfo? File { get; private set; } - - public void Close() - { - Stream?.Dispose(); - try - { - File?.Delete(); - } - catch(IOException exception) - { - Console.WriteLine(exception); - } - Stream = null; - File = null; - } - } - #endregion INCLUDE -} \ No newline at end of file diff --git a/src/ChapterTests.props b/src/ChapterTests.props index f81d48c55..6b2c03dea 100644 --- a/src/ChapterTests.props +++ b/src/ChapterTests.props @@ -18,7 +18,8 @@ - + + diff --git a/src/Shared/CompilerAssert.cs b/src/Shared/CompilerAssert.cs index cfb872d88..17e1575df 100644 --- a/src/Shared/CompilerAssert.cs +++ b/src/Shared/CompilerAssert.cs @@ -3,9 +3,9 @@ using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Scripting; -using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Globalization; using System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace AddisonWesley.Michaelis.EssentialCSharp.Shared; diff --git a/src/Shared/Tests/PowerShellTestUtilities.cs b/src/Shared/Tests/PowerShellTestUtilities.cs index 4a1d8814b..efc83013f 100644 --- a/src/Shared/Tests/PowerShellTestUtilities.cs +++ b/src/Shared/Tests/PowerShellTestUtilities.cs @@ -10,7 +10,7 @@ public static bool WindowsEnvironment() return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); } - public static Lazy _PowerShellCommand = new Lazy(() => + public static Lazy _PowerShellCommand = new(() => { string? powershellCommand = null; // Verify that the PowerShell command executes successfully.