From 0b8c41edbbb4e75128b2b377780735a43a4cfff0 Mon Sep 17 00:00:00 2001 From: Code Maze Date: Sun, 7 Nov 2021 17:49:26 +0100 Subject: [PATCH 1/3] CM-46: Delegates in C# Inital Commit --- .../DelegatesInCsharp/DelegatesInCsharp.sln | 31 ++++++ .../DelegatesInCsharp.csproj | 8 ++ .../DelegatesInCsharp/Program.cs | 53 +++++++++++ .../DelegatesInCsharp/Tests/Tests.cs | 94 +++++++++++++++++++ .../DelegatesInCsharp/Tests/Tests.csproj | 16 ++++ 5 files changed, 202 insertions(+) create mode 100644 csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp.sln create mode 100644 csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/DelegatesInCsharp.csproj create mode 100644 csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs create mode 100644 csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs create mode 100644 csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.csproj diff --git a/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp.sln b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp.sln new file mode 100644 index 0000000000..ea1653648e --- /dev/null +++ b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DelegatesInCsharp", "DelegatesInCsharp\DelegatesInCsharp.csproj", "{B7E7E843-3109-4BFF-90DD-B979CA1853B0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{CAAB0C6D-B8F4-487D-8114-8EAA72D02BEF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B7E7E843-3109-4BFF-90DD-B979CA1853B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7E7E843-3109-4BFF-90DD-B979CA1853B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7E7E843-3109-4BFF-90DD-B979CA1853B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7E7E843-3109-4BFF-90DD-B979CA1853B0}.Release|Any CPU.Build.0 = Release|Any CPU + {CAAB0C6D-B8F4-487D-8114-8EAA72D02BEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAAB0C6D-B8F4-487D-8114-8EAA72D02BEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAAB0C6D-B8F4-487D-8114-8EAA72D02BEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAAB0C6D-B8F4-487D-8114-8EAA72D02BEF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {84A17409-6852-4689-A48E-AE3682E9D105} + EndGlobalSection +EndGlobal diff --git a/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/DelegatesInCsharp.csproj b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/DelegatesInCsharp.csproj new file mode 100644 index 0000000000..1d2d39a9ef --- /dev/null +++ b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/DelegatesInCsharp.csproj @@ -0,0 +1,8 @@ + + + + Exe + net5.0 + + + diff --git a/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs new file mode 100644 index 0000000000..f0a2d10334 --- /dev/null +++ b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DelegatesInCsharp +{ + delegate void PrintMessage(string text); + delegate T Print(T param1); + + class Program + { + public static void WriteText(string text) { Console.WriteLine($"Text: {text}"); } + public static void ReverseWriteText(string text) { Console.WriteLine($"Text in reverse: {Reverse(text)}"); } + public static string ReverseText(string text) { return Reverse(text); } + + private static string Reverse(string s) + { + char[] charArray = s.ToCharArray(); + Array.Reverse(charArray); + return new string(charArray); + } + + static void Main(string[] args) + { + PrintMessage delegate1 = new PrintMessage(WriteText); + PrintMessage delegate2 = new PrintMessage(ReverseWriteText); + // with + sign + PrintMessage multicastDelegate = delegate1 + delegate2; + + // with =, +=, and -= + multicastDelegate = delegate1; + multicastDelegate += delegate2; + + multicastDelegate.Invoke("Go ahead, make my day."); + multicastDelegate("You're gonna need a bigger boat."); + + Print delegate3 = new Print(ReverseText); + Console.WriteLine(delegate3("I'll be back.")); + + Action executeReverseWrite = ReverseWriteText; + executeReverseWrite("You're gonna need a bigger boat."); + + Func executeReverse = ReverseText; + Console.WriteLine(executeReverse("You're gonna need a bigger boat.")); + + // comment out other stuff + Action executeReverseWriteAction = ReverseWriteText; + executeReverseWriteAction("Are you not entertained?"); + Func executeReverseFunc = ReverseText; + Console.WriteLine(executeReverse("Are you not entertained?")); + } + } +} diff --git a/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs new file mode 100644 index 0000000000..447a2a2f01 --- /dev/null +++ b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs @@ -0,0 +1,94 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace Tests +{ + delegate string PrintMessage(string text); + delegate T Print(T param1); + + [TestClass] + public class Tests + { + public static string WriteText(string text) { return $"Text:{text}"; } + public static string ReverseText(string text) { return Reverse(text); } + public static void ReverseWriteText(string text) { Console.WriteLine(Reverse(text)); } + + private static string Reverse(string s) + { + char[] charArray = s.ToCharArray(); + Array.Reverse(charArray); + return new string(charArray); + } + + [TestMethod] + public void whenStringIsSent_DelegateExecutesTheReferencedMethod() + { + PrintMessage delegate1 = new PrintMessage(WriteText); + var result = delegate1("You're gonna need a bigger boat."); + Assert.AreEqual("Text:You're gonna need a bigger boat.", result); + } + + [TestMethod] + public void whenStringIsSent_DelegateReturnsTheReversedString() + { + PrintMessage delegate1 = new PrintMessage(ReverseText); + var result = delegate1("You're gonna need a bigger boat."); + Assert.AreEqual(Reverse("You're gonna need a bigger boat."), result); + } + + [TestMethod] + public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusSign_DelegateInvocationListContainsTwoMethods() + { + PrintMessage delegate1 = new PrintMessage(WriteText); + PrintMessage delegate2 = new PrintMessage(ReverseText); + PrintMessage multicastDelegate = delegate1 + delegate2; + + var invocationList = multicastDelegate.GetInvocationList(); + + Assert.AreEqual(invocationList.Length, 2); + Assert.AreEqual(invocationList[0].Method.Name, "WriteText"); + Assert.AreEqual(invocationList[1].Method.Name, "ReverseText"); + } + + [TestMethod] + public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusEquals_DelegateInvocationListContainsTwoMethods() + { + PrintMessage delegate1 = new PrintMessage(WriteText); + PrintMessage delegate2 = new PrintMessage(ReverseText); + PrintMessage multicastDelegate = delegate1; + multicastDelegate += delegate2; + + var invocationList = multicastDelegate.GetInvocationList(); + + Assert.AreEqual(invocationList.Length, 2); + Assert.AreEqual(invocationList[0].Method.Name, "WriteText"); + Assert.AreEqual(invocationList[1].Method.Name, "ReverseText"); + } + + [TestMethod] + public void whenGenericDelegate_DelegateExecutesTheReferencedMethod() + { + Print delegate1 = new Print(ReverseText); + + var result = delegate1("You're gonna need a bigger boat."); + + Assert.AreEqual(Reverse("You're gonna need a bigger boat."), result); + } + + [TestMethod] + public void whenActionDelegate_DelegateInvocationListNotEmpty() + { + Action executeReverseWriteAction = ReverseWriteText; + var invocationList = executeReverseWriteAction.GetInvocationList(); + Assert.AreEqual(invocationList.Length, 1); + } + + [TestMethod] + public void whenFuncDelegate_DelegateInvocationListNotEmpty() + { + Func executeReverseWriteAction = ReverseText; + var invocationList = executeReverseWriteAction.GetInvocationList(); + Assert.AreEqual(invocationList.Length, 1); + } + } +} diff --git a/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.csproj b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.csproj new file mode 100644 index 0000000000..4203089904 --- /dev/null +++ b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.csproj @@ -0,0 +1,16 @@ + + + + net5.0 + + false + + + + + + + + + + From ae942072a27e6e353bd9ccbd91e3bcc8ce77cc89 Mon Sep 17 00:00:00 2001 From: Code Maze Date: Mon, 8 Nov 2021 15:11:03 +0100 Subject: [PATCH 2/3] Cleaning --- .../DelegatesInCsharp/Program.cs | 26 +++++++------------ .../DelegatesInCsharp/Tests/Tests.cs | 18 ++++++------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs index f0a2d10334..f928217476 100644 --- a/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs +++ b/csharp-advanced-topics/DelegatesInCsharp/DelegatesInCsharp/Program.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; namespace DelegatesInCsharp { @@ -9,9 +7,9 @@ namespace DelegatesInCsharp class Program { - public static void WriteText(string text) { Console.WriteLine($"Text: {text}"); } - public static void ReverseWriteText(string text) { Console.WriteLine($"Text in reverse: {Reverse(text)}"); } - public static string ReverseText(string text) { return Reverse(text); } + public static void WriteText(string text) => Console.WriteLine($"Text: {text}"); + public static void ReverseWriteText(string text) => Console.WriteLine($"Text in reverse: {Reverse(text)}"); + public static string ReverseText(string text) => Reverse(text); private static string Reverse(string s) { @@ -22,10 +20,10 @@ private static string Reverse(string s) static void Main(string[] args) { - PrintMessage delegate1 = new PrintMessage(WriteText); - PrintMessage delegate2 = new PrintMessage(ReverseWriteText); + var delegate1 = new PrintMessage(WriteText); + var delegate2 = new PrintMessage(ReverseWriteText); // with + sign - PrintMessage multicastDelegate = delegate1 + delegate2; + var multicastDelegate = delegate1 + delegate2; // with =, +=, and -= multicastDelegate = delegate1; @@ -34,20 +32,14 @@ static void Main(string[] args) multicastDelegate.Invoke("Go ahead, make my day."); multicastDelegate("You're gonna need a bigger boat."); - Print delegate3 = new Print(ReverseText); + var delegate3 = new Print(ReverseText); Console.WriteLine(delegate3("I'll be back.")); - Action executeReverseWrite = ReverseWriteText; - executeReverseWrite("You're gonna need a bigger boat."); - - Func executeReverse = ReverseText; - Console.WriteLine(executeReverse("You're gonna need a bigger boat.")); - // comment out other stuff Action executeReverseWriteAction = ReverseWriteText; executeReverseWriteAction("Are you not entertained?"); - Func executeReverseFunc = ReverseText; - Console.WriteLine(executeReverse("Are you not entertained?")); + Func executeReverseFunc = ReverseText; + Console.WriteLine(executeReverseFunc("Are you not entertained?")); } } } diff --git a/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs index 447a2a2f01..ce693d6792 100644 --- a/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs +++ b/csharp-advanced-topics/DelegatesInCsharp/Tests/Tests.cs @@ -23,7 +23,7 @@ private static string Reverse(string s) [TestMethod] public void whenStringIsSent_DelegateExecutesTheReferencedMethod() { - PrintMessage delegate1 = new PrintMessage(WriteText); + var delegate1 = new PrintMessage(WriteText); var result = delegate1("You're gonna need a bigger boat."); Assert.AreEqual("Text:You're gonna need a bigger boat.", result); } @@ -31,7 +31,7 @@ public void whenStringIsSent_DelegateExecutesTheReferencedMethod() [TestMethod] public void whenStringIsSent_DelegateReturnsTheReversedString() { - PrintMessage delegate1 = new PrintMessage(ReverseText); + var delegate1 = new PrintMessage(ReverseText); var result = delegate1("You're gonna need a bigger boat."); Assert.AreEqual(Reverse("You're gonna need a bigger boat."), result); } @@ -39,9 +39,9 @@ public void whenStringIsSent_DelegateReturnsTheReversedString() [TestMethod] public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusSign_DelegateInvocationListContainsTwoMethods() { - PrintMessage delegate1 = new PrintMessage(WriteText); - PrintMessage delegate2 = new PrintMessage(ReverseText); - PrintMessage multicastDelegate = delegate1 + delegate2; + var delegate1 = new PrintMessage(WriteText); + var delegate2 = new PrintMessage(ReverseText); + var multicastDelegate = delegate1 + delegate2; var invocationList = multicastDelegate.GetInvocationList(); @@ -53,9 +53,9 @@ public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusSign_DelegateIn [TestMethod] public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusEquals_DelegateInvocationListContainsTwoMethods() { - PrintMessage delegate1 = new PrintMessage(WriteText); - PrintMessage delegate2 = new PrintMessage(ReverseText); - PrintMessage multicastDelegate = delegate1; + var delegate1 = new PrintMessage(WriteText); + var delegate2 = new PrintMessage(ReverseText); + var multicastDelegate = delegate1; multicastDelegate += delegate2; var invocationList = multicastDelegate.GetInvocationList(); @@ -68,7 +68,7 @@ public void givenMulticastDelegate_whenTwoReferencedMethodAndPlusEquals_Delegate [TestMethod] public void whenGenericDelegate_DelegateExecutesTheReferencedMethod() { - Print delegate1 = new Print(ReverseText); + var delegate1 = new Print(ReverseText); var result = delegate1("You're gonna need a bigger boat."); From 5f37385180f90c02646e3a8b6403d6b07ba19adf Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Tue, 11 Aug 2026 11:23:56 +0200 Subject: [PATCH 3/3] ThreadSleepVsTaskDelay: retarget to net10.0, add starvation demo + PeriodicTimer sample --- .../ThreadSleepVsTaskDelay.Test.csproj | 2 +- .../src/ThreadSleepVsTaskDelay/Program.cs | 92 +++++++++++++++---- .../ThreadSleepVsTaskDelay.csproj | 2 +- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay.Test/ThreadSleepVsTaskDelay.Test.csproj b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay.Test/ThreadSleepVsTaskDelay.Test.csproj index 4d1afdba67..32572b642a 100644 --- a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay.Test/ThreadSleepVsTaskDelay.Test.csproj +++ b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay.Test/ThreadSleepVsTaskDelay.Test.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/Program.cs b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/Program.cs index c6b0fcc160..c13129f575 100644 --- a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/Program.cs +++ b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/Program.cs @@ -1,32 +1,84 @@ -using System.Diagnostics; +using System.Diagnostics; -namespace ThreadSleepVsTaskDelay +namespace ThreadSleepVsTaskDelay; + +public class Program { - public class Program + public static async Task UseTaskDelay(int delayMilliseconds = 2000) + { + Console.WriteLine($"Before delay: Thread id = {Environment.CurrentManagedThreadId}"); + await Task.Delay(delayMilliseconds); + Console.WriteLine($"After delay: Thread id = {Environment.CurrentManagedThreadId}"); + } + + public static void UseThreadSleep(int sleepMilliseconds = 2000) + { + Console.WriteLine($"Before sleep: Thread id = {Environment.CurrentManagedThreadId}"); + Thread.Sleep(sleepMilliseconds); + Console.WriteLine($"After sleep: Thread id = {Environment.CurrentManagedThreadId}"); + } + + public static async Task RunBlockingWorkAsync(int workItems, int milliseconds) + { + var stopwatch = Stopwatch.StartNew(); + var blocking = Enumerable.Range(0, workItems) + .Select(_ => Task.Run(() => Thread.Sleep(milliseconds))); + + await Task.WhenAll(blocking); + + return stopwatch.ElapsedMilliseconds; + } + + public static async Task RunNonBlockingWorkAsync(int workItems, int milliseconds) + { + var stopwatch = Stopwatch.StartNew(); + var waiting = Enumerable.Range(0, workItems) + .Select(_ => Task.Delay(milliseconds)); + + await Task.WhenAll(waiting); + + return stopwatch.ElapsedMilliseconds; + } + + private static async Task RefreshCacheAsync() { - public static async Task UseTaskDelay(int sleepMilliseconds = 2000) + await Task.Delay(50); + } + + public static async Task RunPeriodicRefreshAsync(CancellationToken cancellationToken) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1)); + + while (await timer.WaitForNextTickAsync(cancellationToken)) { - Console.WriteLine($"Before delay: Thread id = {Environment.CurrentManagedThreadId}"); - await Task.Delay(sleepMilliseconds); - Console.WriteLine($"After delay: Thread id = {Environment.CurrentManagedThreadId}"); + await RefreshCacheAsync(); // runs every second, no drift, cancellable } + } + + private static async Task Main() + { + Console.WriteLine("Starting Thread.Sleep test..."); + UseThreadSleep(); + Console.WriteLine("Thread.Sleep test completed.\n"); + + Console.WriteLine("Starting Task.Delay test..."); + await UseTaskDelay(); + Console.WriteLine("Task.Delay test completed.\n"); - public static void UseThreadSleep(int delayMilliseconds = 2000) + Console.WriteLine($"Processor count: {Environment.ProcessorCount}"); + var blockingMs = await RunBlockingWorkAsync(50, 1000); + Console.WriteLine($"50 blocking items: {blockingMs} ms"); + var nonBlockingMs = await RunNonBlockingWorkAsync(50, 1000); + Console.WriteLine($"50 non-blocking items: {nonBlockingMs} ms"); + + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3.5)); + try { - Console.WriteLine($"Before sleep: Thread id = {Environment.CurrentManagedThreadId}"); - Thread.Sleep(delayMilliseconds); - Console.WriteLine($"After sleep: Thread id = {Environment.CurrentManagedThreadId}"); + await RunPeriodicRefreshAsync(cts.Token); } - - private static async Task Main() + catch (OperationCanceledException) { - Console.WriteLine("Starting Thread.Sleep test..."); - UseThreadSleep(); - Console.WriteLine("Thread.Sleep test completed.\n"); - - Console.WriteLine("Starting Task.Delay test..."); - await UseTaskDelay(); - Console.WriteLine("Task.Delay test completed."); + Console.WriteLine("Periodic refresh canceled."); } } } diff --git a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/ThreadSleepVsTaskDelay.csproj b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/ThreadSleepVsTaskDelay.csproj index fbb4a9b9a4..5de8ecb546 100644 --- a/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/ThreadSleepVsTaskDelay.csproj +++ b/threads-csharp/ThreadSleepVsTaskDelay/src/ThreadSleepVsTaskDelay/ThreadSleepVsTaskDelay.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable true