diff --git a/.gitignore b/.gitignore
index 2c338fe..c78bde7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -358,3 +358,6 @@ NuGet.config
# MacOS files
.DS_Store
**/.trydotnet-builderror
+
+# NCrunch
+*ncrunch*
diff --git a/Documentation/Revisit.md b/Documentation/Revisit.md
new file mode 100644
index 0000000..c28746c
--- /dev/null
+++ b/Documentation/Revisit.md
@@ -0,0 +1,16 @@
+1. Where static value type member is allocated?
+**On `Loader Heap`**. It can be shared by multiple threads. It is not boxed. It is not allocated on the stack.
+ [**SO question*](https://stackoverflow.com/questions/25741795/is-a-static-value-type-field-boxed-in-the-heap-in-c)
+
+1. What is the advantage of `Task` over `Thread`?
+
+1. `SynchronizationContext`
+
+ https://docs.microsoft.com/en-us/archive/msdn-magazine/2011/february/msdn-magazine-parallel-computing-it-s-all-about-the-synchronizationcontext
+
+ > 1) One aspect of SynchronizationContext is that it provides a way to queue a unit of work to a context. Note that this unit of work is queued to a context rather than a specific thread.
+
+
+ > 2) Another aspect of SynchronizationContext is that every thread has a “current” context. A thread’s context isn’t necessarily unique; its context instance may be shared with other threads. It’s possible for a thread to change its current context, but this is quite rare.
+
+ > 3) A third aspect of SynchronizationContext is that it **keeps a count of** outstanding asynchronous operations.
\ No newline at end of file
diff --git a/csharp8/CodingGame.Enemy/CodingGame.Enemy.csproj b/csharp8/CodingGame.Enemy/CodingGame.Enemy.csproj
new file mode 100644
index 0000000..d453e9a
--- /dev/null
+++ b/csharp8/CodingGame.Enemy/CodingGame.Enemy.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
diff --git a/csharp8/CodingGame.Enemy/Player.cs b/csharp8/CodingGame.Enemy/Player.cs
new file mode 100644
index 0000000..60f2306
--- /dev/null
+++ b/csharp8/CodingGame.Enemy/Player.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Linq;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+/**
+ * The code below will read all the game information for you.
+ * On each game turn, information will be available on the standard input, you will be sent:
+ * -> the total number of visible enemies
+ * -> for each enemy, its name and distance from you
+ * The system will wait for you to write an enemy name on the standard output.
+ * Once you have designated a target:
+ * -> the cannon will shoot
+ * -> the enemies will move
+ * -> new info will be available for you to read on the standard input.
+ *
+ *
+ *
+ * Votre programme doit détruire les vaisseaux ennemis en tirant sur l'ennemi le plus proche à chaque tour.
+ Règles
+ Les vaisseaux ennemis approchent en ligne droite vers votre canon.
+
+ À chaque début d'un tour de jeu (dans la boucle game loop), vous obtenez les informations des deux ennemis
+ les plus proches :
+ variable enemy1 : le nom de l'ennemi 1.
+ variable dist1 : la distance à laquelle se trouve l'ennemi 1.
+ variable enemy2 : le nom de l'ennemi 2.
+ variable dist2 : la distance à laquelle se trouve l'ennemi 2.
+ Avant la fin du tour (fin de la boucle), vous devez indiquer en sortie le nom de l'ennemi le plus proche.
+ Pour afficher le nom de l'ennemi le plus proche, vous devez utiliser la variable enemy1 ou enemy2.
+ **/
+class Player
+{
+
+ static void Main(string[] args)
+ {
+ // game loop
+ while (true)
+ {
+
+ int minDistance = 1000;
+ string closestEnemy = null;
+
+
+ if (!int.TryParse(Console.ReadLine(), out int count))
+ {
+ Console.WriteLine("Invalid arguments.");
+ continue;
+ }
+
+ for (int i = 0; i < count; i++)
+ {
+ try
+ {
+ (string enemy, int dist) = ParseEnemyInfo(Console.ReadLine());
+ if (dist < minDistance)
+ {
+ minDistance = dist;
+ closestEnemy = enemy;
+ }
+ }
+ catch (ArgumentException)
+ {
+ Console.WriteLine("Invalid arguments.");
+ continue;
+ }
+
+ }
+
+ // Write an action using Console.WriteLine()
+ // To debug: Console.Error.WriteLine("Debug messages...");
+ Console.Out.WriteLine(closestEnemy);
+ //Console.WriteLine("HotDroid"); // The name of the most threatening enemy (HotDroid is just one example)
+ }
+ }
+
+ private static (string enemy, int dist) ParseEnemyInfo(string rawEnemy)
+ {
+ string[] components = Regex.Split(rawEnemy, @"\s+");
+ if (components.Length != 2
+ || !int.TryParse(components[1].Substring(0, components[1].Length - 1), out int distance))
+ {
+ throw new ArgumentException("Invalid enemy info");
+ }
+
+ var enemy = components[0];
+ return (enemy, distance);
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/AsyncStreamShould.cs b/csharp8/ExploreCsharpEight.Tests/AsyncStreamShould.cs
new file mode 100644
index 0000000..fee272b
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/AsyncStreamShould.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using NFluent;
+using NUnit.Framework;
+
+namespace ExploreCsharpEight.Tests
+{
+ [TestFixture]
+ public class AsyncStreamShould
+ {
+ public static async System.Collections.Generic.IAsyncEnumerable GenerateSequence()
+ {
+ for (int i = 0; i < 20; i++)
+ {
+ await Task.Delay(1);
+ yield return i;
+ }
+ }
+
+ public async Task> Consume(IAsyncEnumerable stream)
+ {
+ var list = new List();
+ await foreach (var i in stream)
+ {
+ list.Add(i);
+ }
+
+ return list;
+ }
+
+ [Test]
+ public async Task Can_get_future_list()
+ {
+ var result = await Consume(GenerateSequence());
+ Check.That(result).ContainsExactly(Enumerable.Range(0, 20));
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/Event.cs b/csharp8/ExploreCsharpEight.Tests/Event.cs
new file mode 100644
index 0000000..7d7c98c
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/Event.cs
@@ -0,0 +1,15 @@
+namespace ExploreCsharpEight.Tests
+{
+ public abstract class Event
+ {
+
+ }
+
+ public class OrderReceived : Event
+ {
+ }
+
+ public class OrderAccepted : Event
+ {
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/ExploreCsharpEight.Tests.csproj b/csharp8/ExploreCsharpEight.Tests/ExploreCsharpEight.Tests.csproj
new file mode 100644
index 0000000..bdde144
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/ExploreCsharpEight.Tests.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netcoreapp3.1
+ 8.0
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csharp8/ExploreCsharpEight.Tests/PatternMatchingCSharp7Should.cs b/csharp8/ExploreCsharpEight.Tests/PatternMatchingCSharp7Should.cs
new file mode 100644
index 0000000..3f0ee85
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/PatternMatchingCSharp7Should.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace ExploreCsharpEight.Tests
+{
+
+ public class PatternMatchingCSharp7Should
+ {
+ public class OrderManager
+ {
+ public void Notify(Event evt)
+ {
+ switch (evt)
+ {
+ case OrderReceived orderReceived:
+ Handle(orderReceived);
+ break;
+ case OrderAccepted orderAccepted:
+ Handle(orderAccepted);
+ break;
+ default:
+ throw new ArgumentException();
+ }
+ }
+
+ private void Handle(OrderReceived orderReceived)
+ {
+ }
+
+ private void Handle(OrderAccepted orderAccepted)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/RegularExpressionShould.cs b/csharp8/ExploreCsharpEight.Tests/RegularExpressionShould.cs
new file mode 100644
index 0000000..06a083e
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/RegularExpressionShould.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Text.RegularExpressions;
+using NFluent;
+using NUnit.Framework;
+using NUnit.Framework.Internal;
+
+namespace ExploreCsharpEight.Tests
+{
+ [TestFixture]
+ public class RegularExpressionShould
+ {
+ [TestCase("toto 15", true)]
+ [TestCase("toto6966 15", true)]
+ [TestCase("toto6966 15d", false)]
+ [TestCase("toto6966 15", true)]
+ [TestCase("42 15", true)]
+ public void Match_string_space_integer(string input, bool expectedMatch)
+ {
+ var regex = new Regex(@"^\w+\s+\d+$");
+ bool match = regex.IsMatch(input);
+
+ Check.That(match).IsEqualTo(expectedMatch);
+ }
+
+ [Test]
+ public void Match_one_value()
+ {
+ // Step 1: create new Regex.
+ Regex regex = new Regex(@"\d+");
+
+ // Step 2: call Match on Regex instance.
+ Match match = regex.Match("Dot 55 Perls");
+
+ // Step 3: test for Success.
+ if (match.Success)
+ {
+ Console.WriteLine("MATCH VALUE: " + match.Value);
+ }
+ }
+
+ [Test]
+ public void Take_out_matching_values()
+ {
+ // Part 1: the input string.
+ string input = "/content/alternate-1.aspx";
+
+ // Part 2: call Regex.Match.
+ Match match = Regex.Match(input, @"content/([A-Za-z0-9\-]+)\.aspx$",
+ RegexOptions.IgnoreCase);
+
+ // Part 3: check the Match for Success.
+ if(!match.Success)
+ Assert.Fail("Not match");
+
+
+ // Part 4: get the Group value and display it.
+ Check.That(match.Groups).HasSize(2);
+
+ Check.That(match.Groups[0].Value).IsEqualTo("content/alternate-1.aspx");
+ Check.That(match.Groups[1].Value).IsEqualTo("alternate-1");
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/TaskYieldShould.cs b/csharp8/ExploreCsharpEight.Tests/TaskYieldShould.cs
new file mode 100644
index 0000000..6b024f4
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/TaskYieldShould.cs
@@ -0,0 +1,41 @@
+using System.Threading;
+using System.Threading.Tasks;
+using NFluent;
+using NUnit.Framework;
+
+namespace ExploreCsharpEight.Tests
+{
+ [TestFixture]
+ public class TaskYieldShould
+ {
+ [Test]
+ public async Task Without_task_yield_actually_get_a_real_blocking_method_call()
+ {
+ var capture = Thread.CurrentThread.ManagedThreadId;
+ var threadOfAsyncOp = await DoFakeAsync();
+ Check.That(threadOfAsyncOp).IsEqualTo(capture);
+ }
+
+ [Test]
+ public async Task With_task_yield()
+ {
+ var capture = Thread.CurrentThread.ManagedThreadId;
+
+ await Task.Yield(); // Task.Yield force to the await operation to start in a different thread.
+ // https://stackoverflow.com/questions/22645024/when-would-i-use-task-yield
+
+ var threadOfAsyncOp = await DoFakeAsync();
+ Check.That(threadOfAsyncOp).IsNotEqualTo(capture);
+ }
+
+ ///
+ /// Nothing can ensure under the cover of async modifier, it is really a non blocking operation.
+ ///
+ ///
+ private async Task DoFakeAsync()
+ {
+ Thread.Sleep(1);
+ return Thread.CurrentThread.ManagedThreadId;
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight.Tests/TasksShould.cs b/csharp8/ExploreCsharpEight.Tests/TasksShould.cs
new file mode 100644
index 0000000..79968b3
--- /dev/null
+++ b/csharp8/ExploreCsharpEight.Tests/TasksShould.cs
@@ -0,0 +1,59 @@
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using NFluent;
+using NUnit.Framework;
+
+namespace ExploreCsharpEight.Tests
+{
+ [TestFixture]
+ public class TasksShould
+ {
+ [Test]
+ public async Task Task_continuation_runs_on_a_thread_pool_thread()
+ {
+ var beforeThreadId = Thread.CurrentThread.ManagedThreadId;
+ await Task.Delay(1);
+
+ var afterThreadId = Thread.CurrentThread.ManagedThreadId;
+ Check.That(afterThreadId).IsNotEqualTo(beforeThreadId); // Well they can be different
+ }
+
+ [Test]
+ public async Task Can_force_continuation_take_place_on_the_initial_synchronizationContext()
+ {
+ Check.That(SynchronizationContext.Current).IsNull();
+
+ SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
+
+ Check.That(SynchronizationContext.Current).IsNotNull();
+
+ var captureSyncContext = SynchronizationContext.Current;
+
+ var beforeThreadId = Thread.CurrentThread.ManagedThreadId;
+ await Task.Run(async () => await Task.Delay(1))
+ .ContinueWith((t, o) =>
+ {
+ var afterThreadId = Thread.CurrentThread.ManagedThreadId;
+ Check.That(afterThreadId).IsNotEqualTo(beforeThreadId); // Well they can be different
+
+
+ }, null, TaskScheduler.FromCurrentSynchronizationContext());
+
+ Check.That(Thread.CurrentThread.ManagedThreadId).IsNotEqualTo(beforeThreadId);
+ Check.That(SynchronizationContext.Current).IsNotEqualTo(captureSyncContext);
+ Check.That(SynchronizationContext.Current).IsNull();
+ }
+
+ [Test]
+ public async Task Can_not_force_continuation_on_initial_thread()
+ {
+ var beforeThreadId = Thread.CurrentThread.ManagedThreadId;
+
+ await Task.Delay(10).ConfigureAwait(continueOnCapturedContext: true);
+
+ var afterThreadId = Thread.CurrentThread.ManagedThreadId;
+ Check.That(afterThreadId).IsNotEqualTo(beforeThreadId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp8/ExploreCsharpEight/ExploreCsharpEight.sln b/csharp8/ExploreCsharpEight/ExploreCsharpEight.sln
new file mode 100644
index 0000000..d727a6f
--- /dev/null
+++ b/csharp8/ExploreCsharpEight/ExploreCsharpEight.sln
@@ -0,0 +1,55 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29920.165
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExploreCsharpEight", "ExploreCsharpEight.csproj", "{21BECE14-ED87-4D48-A399-27EA8F2B480A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExploreCsharpEight.Tests", "..\ExploreCsharpEight.Tests\ExploreCsharpEight.Tests.csproj", "{18F78165-32A4-42DC-90FE-70CBDEB09E97}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tasks.ConsoleApp", "..\Tasks.Console\Tasks.ConsoleApp.csproj", "{ADBEB077-2B48-4466-84C3-067DE3A50AA4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApp", "..\WebApp\WebApp.csproj", "{704F4867-DC4F-4568-A31D-9E89C321DE8E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsFormsApp", "..\WindowsFormsApp\WindowsFormsApp.csproj", "{334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodingGame.Enemy", "..\CodingGame.Enemy\CodingGame.Enemy.csproj", "{70EEECEA-E3DA-415A-9C1C-0BE6474F4153}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {21BECE14-ED87-4D48-A399-27EA8F2B480A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {21BECE14-ED87-4D48-A399-27EA8F2B480A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {21BECE14-ED87-4D48-A399-27EA8F2B480A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {21BECE14-ED87-4D48-A399-27EA8F2B480A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {18F78165-32A4-42DC-90FE-70CBDEB09E97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {18F78165-32A4-42DC-90FE-70CBDEB09E97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {18F78165-32A4-42DC-90FE-70CBDEB09E97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {18F78165-32A4-42DC-90FE-70CBDEB09E97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ADBEB077-2B48-4466-84C3-067DE3A50AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ADBEB077-2B48-4466-84C3-067DE3A50AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ADBEB077-2B48-4466-84C3-067DE3A50AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ADBEB077-2B48-4466-84C3-067DE3A50AA4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {704F4867-DC4F-4568-A31D-9E89C321DE8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {704F4867-DC4F-4568-A31D-9E89C321DE8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {704F4867-DC4F-4568-A31D-9E89C321DE8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {704F4867-DC4F-4568-A31D-9E89C321DE8E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}.Release|Any CPU.Build.0 = Release|Any CPU
+ {70EEECEA-E3DA-415A-9C1C-0BE6474F4153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {70EEECEA-E3DA-415A-9C1C-0BE6474F4153}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {70EEECEA-E3DA-415A-9C1C-0BE6474F4153}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {70EEECEA-E3DA-415A-9C1C-0BE6474F4153}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B96EC500-418B-4550-AFE4-6302F967773B}
+ EndGlobalSection
+EndGlobal
diff --git a/csharp8/Tasks.Console/Program.cs b/csharp8/Tasks.Console/Program.cs
new file mode 100644
index 0000000..13a9b69
--- /dev/null
+++ b/csharp8/Tasks.Console/Program.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Tasks.ConsoleApp
+{
+ class Program
+ {
+ static async Task Main(string[] args)
+ {
+ SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
+
+ var beforeThreadId = Thread.CurrentThread.ManagedThreadId;
+ await Task.Run(async () => await Task.Delay(1))
+ .ContinueWith((t, o) =>
+ {
+ var afterThreadId = Thread.CurrentThread.ManagedThreadId;
+
+ Console.WriteLine($"Before = {beforeThreadId}; Continuation = {afterThreadId}");
+
+ }, null, TaskScheduler.FromCurrentSynchronizationContext());
+
+ }
+ }
+}
diff --git a/csharp8/Tasks.Console/Tasks.ConsoleApp.csproj b/csharp8/Tasks.Console/Tasks.ConsoleApp.csproj
new file mode 100644
index 0000000..d453e9a
--- /dev/null
+++ b/csharp8/Tasks.Console/Tasks.ConsoleApp.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
diff --git a/csharp8/WebApp/Controllers/WeatherForecastController.cs b/csharp8/WebApp/Controllers/WeatherForecastController.cs
new file mode 100644
index 0000000..f1366e7
--- /dev/null
+++ b/csharp8/WebApp/Controllers/WeatherForecastController.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+namespace WebApp.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class WeatherForecastController : ControllerBase
+ {
+ private static readonly string[] Summaries = new[]
+ {
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ };
+
+ private readonly ILogger _logger;
+
+ public WeatherForecastController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public async Task> Get()
+ {
+ SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
+ _logger.LogDebug($"Current sync context = {SynchronizationContext.Current}, isNull = {SynchronizationContext.Current == null}");
+
+
+ var beforeThread = Thread.CurrentThread.ManagedThreadId;
+
+ var continueOnCapturedContext = false;
+
+ var forecastedDays = await Forecast(new WeatherForecast { CapturedInitialThread = beforeThread })
+ .ConfigureAwait(continueOnCapturedContext);
+
+ _logger.LogDebug($"{Thread.CurrentThread.ManagedThreadId} - After completed. ");
+
+
+ return forecastedDays;
+ }
+
+ private async Task> Forecast(WeatherForecast weatherForecast)
+ {
+ var uri = new Uri("http://www.google.com");
+ var client = new HttpClient {BaseAddress = uri};
+
+ _logger.LogDebug($"{Thread.CurrentThread.ManagedThreadId} - In task, Before await. ");
+ _logger.LogDebug($"Get HTTP Response {(await client.GetAsync(uri)).GetHashCode()}");
+
+ _logger.LogDebug($"{Thread.CurrentThread.ManagedThreadId} - In task, After await. ");
+ var rng = new Random();
+ return Enumerable.Range(1, 5).Select(index =>
+ {
+ return weatherForecast.With(w => w.Date = DateTime.Now.AddDays(index))
+ .With(w => w.TemperatureC = rng.Next(-20, 55))
+ .With(w => w.Summary = Summaries[rng.Next(Summaries.Length)]);
+ }).ToArray();
+ }
+ }
+}
diff --git a/csharp8/WebApp/Program.cs b/csharp8/WebApp/Program.cs
new file mode 100644
index 0000000..bb2ae1a
--- /dev/null
+++ b/csharp8/WebApp/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace WebApp
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/csharp8/WebApp/Properties/launchSettings.json b/csharp8/WebApp/Properties/launchSettings.json
new file mode 100644
index 0000000..28a32f5
--- /dev/null
+++ b/csharp8/WebApp/Properties/launchSettings.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+
+ "profiles": {
+
+ "WebApp": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/csharp8/WebApp/Startup.cs b/csharp8/WebApp/Startup.cs
new file mode 100644
index 0000000..ad03128
--- /dev/null
+++ b/csharp8/WebApp/Startup.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.HttpsPolicy;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace WebApp
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseHttpsRedirection();
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
diff --git a/csharp8/WebApp/WeatherForecast.cs b/csharp8/WebApp/WeatherForecast.cs
new file mode 100644
index 0000000..495087c
--- /dev/null
+++ b/csharp8/WebApp/WeatherForecast.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace WebApp
+{
+ public class WeatherForecast
+ {
+ public DateTime Date { get; set; }
+
+ public int TemperatureC { get; set; }
+
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+ public string Summary { get; set; }
+
+ public int CapturedInitialThread { get; set; }
+
+ public WeatherForecast With(Action modify)
+ {
+ modify(this);
+ return this;
+ }
+ }
+}
diff --git a/csharp8/WebApp/WebApp.csproj b/csharp8/WebApp/WebApp.csproj
new file mode 100644
index 0000000..c934769
--- /dev/null
+++ b/csharp8/WebApp/WebApp.csproj
@@ -0,0 +1,10 @@
+
+
+
+ netcoreapp3.1
+ Windows
+ ..\ExploreCsharpEight
+
+
+
+
diff --git a/csharp8/WebApp/appsettings.Development.json b/csharp8/WebApp/appsettings.Development.json
new file mode 100644
index 0000000..e2026c4
--- /dev/null
+++ b/csharp8/WebApp/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/csharp8/WebApp/appsettings.json b/csharp8/WebApp/appsettings.json
new file mode 100644
index 0000000..81ff877
--- /dev/null
+++ b/csharp8/WebApp/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/csharp8/WindowsFormsApp/App.config b/csharp8/WindowsFormsApp/App.config
new file mode 100644
index 0000000..5754728
--- /dev/null
+++ b/csharp8/WindowsFormsApp/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csharp8/WindowsFormsApp/FormConfigureAwait.Designer.cs b/csharp8/WindowsFormsApp/FormConfigureAwait.Designer.cs
new file mode 100644
index 0000000..fd7430e
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormConfigureAwait.Designer.cs
@@ -0,0 +1,85 @@
+namespace WindowsFormsApp
+{
+ partial class FormConfigureAwait
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.button1 = new System.Windows.Forms.Button();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.button2 = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(108, 24);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(380, 52);
+ this.button1.TabIndex = 0;
+ this.button1.Text = "button1";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // textBox1
+ //
+ this.textBox1.Location = new System.Drawing.Point(108, 198);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(380, 20);
+ this.textBox1.TabIndex = 1;
+ //
+ // button2
+ //
+ this.button2.Location = new System.Drawing.Point(108, 102);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(380, 55);
+ this.button2.TabIndex = 2;
+ this.button2.Text = "button2";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // Form1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(601, 316);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.button1);
+ this.Name = "Form1";
+ this.Text = "Form1";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Button button2;
+ }
+}
+
diff --git a/csharp8/WindowsFormsApp/FormConfigureAwait.cs b/csharp8/WindowsFormsApp/FormConfigureAwait.cs
new file mode 100644
index 0000000..1ac526b
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormConfigureAwait.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Diagnostics;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace WindowsFormsApp
+{
+ public partial class FormConfigureAwait : Form
+ {
+ public FormConfigureAwait()
+ {
+ InitializeComponent();
+ }
+
+ private string ThreadId()
+ {
+ return Thread.CurrentThread.ManagedThreadId.ToString( );}
+
+ private async void button1_Click(object sender, EventArgs e)
+ {
+ Debug.WriteLine($"Main: {ThreadId()}");
+ var hash = await DownloadGoogle()
+ .ConfigureAwait(true); // This is default behaviour
+ // Equivalent to: var hash = await DownloadGoogle()
+
+ Debug.WriteLine($"Write hash: {ThreadId()}");
+ this.textBox1.Text = hash;
+ }
+
+ private async Task DownloadGoogle()
+ {
+ var uri = new Uri("http://www.google.com");
+ var client = new HttpClient { BaseAddress = uri };
+
+ Debug.WriteLine($"Before download: {ThreadId()}");
+
+ var downloadGoogle = (await client.GetAsync(uri)).GetHashCode().ToString();
+
+ Debug.WriteLine($"After download: {ThreadId()}");
+ return downloadGoogle;
+ }
+
+ private async void button2_Click(object sender, EventArgs e)
+ {
+ Debug.WriteLine($"Main: {ThreadId()}");
+ await DownloadGoogle().ContinueWith(async (Task task, object state) =>
+ {
+ var hash = await task;
+ Debug.WriteLine($"Write hash: {ThreadId()}");
+ this.textBox1.Text = hash;
+ }, null, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+ }
+}
diff --git a/csharp8/WindowsFormsApp/FormConfigureAwait.resx b/csharp8/WindowsFormsApp/FormConfigureAwait.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormConfigureAwait.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/csharp8/WindowsFormsApp/FormLongRunningInit.Designer.cs b/csharp8/WindowsFormsApp/FormLongRunningInit.Designer.cs
new file mode 100644
index 0000000..5fb61a8
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormLongRunningInit.Designer.cs
@@ -0,0 +1,60 @@
+namespace WindowsFormsApp
+{
+ partial class FormLongRunningInit
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.button1 = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(145, 123);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(510, 92);
+ this.button1.TabIndex = 0;
+ this.button1.Text = "Try click me, u\'ll WAIT.";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // FormLongRunningInit
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(800, 450);
+ this.Controls.Add(this.button1);
+ this.Name = "FormLongRunningInit";
+ this.Text = "FormLongRunningInit";
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button button1;
+ }
+}
\ No newline at end of file
diff --git a/csharp8/WindowsFormsApp/FormLongRunningInit.cs b/csharp8/WindowsFormsApp/FormLongRunningInit.cs
new file mode 100644
index 0000000..933df57
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormLongRunningInit.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace WindowsFormsApp
+{
+ public partial class FormLongRunningInit : Form
+ {
+ public FormLongRunningInit()
+ {
+ InitializeComponent();
+ }
+
+ private int ExecuteFooOnUIThread()
+ {
+ Thread.Sleep(TimeSpan.FromSeconds(10));
+ return 42;
+ }
+
+ ///
+ /// Approved nothing on https://stackoverflow.com/questions/22645024/when-would-i-use-task-yield
+ ///
+ private async void button1_Click(object sender, EventArgs e)
+ {
+ await Task.Yield(); // Make us async right away
+
+ var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later
+
+ await UseDataAsync(data);
+ }
+
+ private async Task UseDataAsync(int data)
+ {
+ await Task.Delay(1);
+ MessageBox.Show($"Finish. {data}");
+ }
+ }
+}
diff --git a/csharp8/WindowsFormsApp/FormLongRunningInit.resx b/csharp8/WindowsFormsApp/FormLongRunningInit.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/csharp8/WindowsFormsApp/FormLongRunningInit.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/csharp8/WindowsFormsApp/Program.cs b/csharp8/WindowsFormsApp/Program.cs
new file mode 100644
index 0000000..97000ba
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace WindowsFormsApp
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new FormLongRunningInit());
+ }
+ }
+}
diff --git a/csharp8/WindowsFormsApp/Properties/AssemblyInfo.cs b/csharp8/WindowsFormsApp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8c6601c
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WindowsFormsApp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("WindowsFormsApp")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("334dbdc4-a8a4-4e83-a68b-a8bcdad8c191")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/csharp8/WindowsFormsApp/Properties/Resources.Designer.cs b/csharp8/WindowsFormsApp/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..d6f629c
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WindowsFormsApp.Properties
+{
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsFormsApp.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/csharp8/WindowsFormsApp/Properties/Resources.resx b/csharp8/WindowsFormsApp/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/csharp8/WindowsFormsApp/Properties/Settings.Designer.cs b/csharp8/WindowsFormsApp/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..fc4be97
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WindowsFormsApp.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/csharp8/WindowsFormsApp/Properties/Settings.settings b/csharp8/WindowsFormsApp/Properties/Settings.settings
new file mode 100644
index 0000000..abf36c5
--- /dev/null
+++ b/csharp8/WindowsFormsApp/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/csharp8/WindowsFormsApp/WindowsFormsApp.csproj b/csharp8/WindowsFormsApp/WindowsFormsApp.csproj
new file mode 100644
index 0000000..127f5fa
--- /dev/null
+++ b/csharp8/WindowsFormsApp/WindowsFormsApp.csproj
@@ -0,0 +1,92 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {334DBDC4-A8A4-4E83-A68B-A8BCDAD8C191}
+ WinExe
+ WindowsFormsApp
+ WindowsFormsApp
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ FormConfigureAwait.cs
+
+
+ Form
+
+
+ FormLongRunningInit.cs
+
+
+
+
+ FormConfigureAwait.cs
+
+
+ FormLongRunningInit.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
\ No newline at end of file