diff --git a/.gitignore b/.gitignore
index 6b9b3e4..5ba042c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,9 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# VS Code folder:
+**/.vscode/
+
# Mono auto generated files
mono_crash.*
@@ -350,3 +353,4 @@ MigrationBackup/
# binlog files for dotnet-try
**/*.binlog
+NuGet.config
diff --git a/csharp7/ExploreCsharpSeven/ExploreCsharpSeven.csproj b/csharp7/ExploreCsharpSeven/ExploreCsharpSeven.csproj
new file mode 100644
index 0000000..d18f168
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/ExploreCsharpSeven.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ netcoreapp3.0
+ 8.0
+ enable
+
+
+
+
+
+
+
diff --git a/csharp7/ExploreCsharpSeven/GenericConstraints.cs b/csharp7/ExploreCsharpSeven/GenericConstraints.cs
new file mode 100644
index 0000000..62bfe75
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/GenericConstraints.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+
+namespace ExploreCsharpSeven
+{
+ public static class GenericConstraints
+ {
+ #region DeclareEnumConstraint
+ public static Dictionary EnumNamedValues() where T : System.Enum
+ {
+ var result = new Dictionary();
+ var values = Enum.GetValues(typeof(T));
+
+ foreach (int item in values)
+ result.Add(item, Enum.GetName(typeof(T), item));
+ return result;
+ }
+ #endregion
+
+ #region DeclareEnum
+ enum Rainbow
+ {
+ Red,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Indigo,
+ Violet
+ }
+ #endregion
+
+ public static int TestEnumNamedValues()
+ {
+ #region TestMapEnumValues
+ var map = EnumNamedValues();
+
+ foreach (var pair in map)
+ Console.WriteLine($"{pair.Key}:\t{pair.Value}");
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/GenericPatterns.cs b/csharp7/ExploreCsharpSeven/GenericPatterns.cs
new file mode 100644
index 0000000..409774d
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/GenericPatterns.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ExploreCsharpSeven
+{
+ static class GenericPatterns
+ {
+ #region GenericSwitchTypePattern
+ public static void TestType(object obj)
+ {
+ switch (obj)
+ {
+ case 5:
+ Console.WriteLine("The object is 5");
+ break;
+ case int i:
+ Console.WriteLine($"The object is an integer: {i}");
+ break;
+ case null:
+ Console.WriteLine($"The object is null");
+ break;
+ case long l:
+ Console.WriteLine($"The object is a long: {l}");
+ break;
+ case double d:
+ Console.WriteLine($"The object is a double: {d}");
+ break;
+ case string s when s.StartsWith("This"):
+ Console.WriteLine($"This was a string that started with the word 'This': {s}");
+ break;
+ case string s when s.StartsWith("This"):
+ Console.WriteLine($"This was a string that started with the word 'This': {s}");
+ break;
+ case string s:
+ Console.WriteLine($"The object is a string: {s}");
+ break;
+ default:
+ Console.WriteLine($"The object is some other type");
+ break;
+ }
+ }
+ #endregion
+
+ public static int CallTestType()
+ {
+ #region GenericTestTypeWithSwitch
+ TestType(5);
+ long longValue = 12;
+ TestType(longValue);
+ int? answer = 42;
+ TestType(answer);
+ double pi = 3.14;
+ TestType(pi);
+ string sum = "12";
+ TestType(sum);
+ answer = null;
+ TestType(answer);
+ string message = "This is a longer message";
+ TestType(message);
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/InReadonly.cs b/csharp7/ExploreCsharpSeven/InReadonly.cs
new file mode 100644
index 0000000..52aa2e7
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/InReadonly.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace ExploreCsharpSeven
+{
+
+ static class InReadonly
+ {
+ #region PointStructure
+ public struct Point3D
+ {
+ private static Point3D origin = new Point3D(0, 0, 0);
+
+ public static Point3D Origin => origin;
+
+ public double X { get; }
+ public double Y { get; }
+ public double Z { get; }
+
+ private double? distance;
+
+ public Point3D(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ distance = null;
+ }
+
+ public double ComputeDistance()
+ {
+ if (!distance.HasValue)
+ distance = Math.Sqrt(X * X + Y * Y + Z * Z);
+ return distance.Value;
+ }
+
+ public static Point3D Translate(in Point3D source, double dX, double dY, double dZ) =>
+ new Point3D(source.X + dX, source.Y + dY, source.Z + dZ);
+
+ public override string ToString()
+ => $"({X}, {Y}, {Z})";
+ }
+ #endregion
+
+ public static int ModifyTheOrigin()
+ {
+ #region UsePointstructure
+ var start = Point3D.Origin;
+ Console.WriteLine($"Start at the origin: {start}");
+
+ // Move the start:
+ start = Point3D.Translate(in start, 5, 5, 5);
+ Console.WriteLine($"Translate by (5,5,5): {start}");
+
+ Console.WriteLine($"Check the origin again: {Point3D.Origin}");
+ #endregion
+ return 0;
+ }
+
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/IsExpressions.cs b/csharp7/ExploreCsharpSeven/IsExpressions.cs
new file mode 100644
index 0000000..0755595
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/IsExpressions.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace ExploreCsharpSeven
+{
+ static class IsExpressions
+ {
+ public static int ExploreIsPattern()
+ {
+ #region IsTypePattern
+ object count = 5;
+
+ if (count is int number)
+ Console.WriteLine(number);
+ else
+ Console.WriteLine($"{count} is not an integer");
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/LocalFunctions.cs b/csharp7/ExploreCsharpSeven/LocalFunctions.cs
new file mode 100644
index 0000000..b3666fe
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/LocalFunctions.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ExploreCsharpSeven
+{
+ class LocalFunctions
+ {
+ #region LocalFunctionFactorial
+ public static int CalculateFactorial(int n)
+ {
+ return nthFactorial(n);
+
+ int nthFactorial(int number) => (number < 2) ?
+ 1 : number * nthFactorial(number - 1);
+ }
+ #endregion
+
+ public static int TestLocalFactorial()
+ {
+ #region LocalFunctionFactorialTest
+ Console.WriteLine(CalculateFactorial(6));
+ #endregion
+ return 0;
+ }
+
+ #region LocalFuntionIteratorMethod
+ static IEnumerable AlphabetSubset(char start, char end)
+ {
+ if (start < 'a' || start > 'z')
+ throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
+ if (end < 'a' || end > 'z')
+ throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
+
+ if (end <= start)
+ throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");
+ for (var c = start; c < end; c++)
+ yield return c;
+ }
+ #endregion
+
+ #region LocalFunctionIteratorWithLocal
+ static IEnumerable AlphabetSubsetLocal(char start, char end)
+ {
+ if (start < 'a' || start > 'z')
+ throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
+ if (end < 'a' || end > 'z')
+ throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
+
+ if (end <= start)
+ throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");
+
+ return alphabetSubsetImplementation();
+
+ IEnumerable alphabetSubsetImplementation()
+ {
+ for (var c = start; c < end; c++)
+ yield return c;
+ }
+ }
+ #endregion
+
+
+
+ public static int TestSubset()
+ {
+ #region LocalFunctionsIteratorTest
+ try
+ {
+ var resultSet1 = AlphabetSubset('d', 'r');
+ var resultSet2 = AlphabetSubset('f', 'a');
+ Console.WriteLine("iterators created");
+ foreach (var thing1 in resultSet1)
+ Console.Write($"{thing1}, ");
+ Console.WriteLine();
+ foreach (var thing2 in resultSet2)
+ Console.Write($"{thing2}, ");
+ Console.WriteLine();
+ }
+ catch (ArgumentException)
+ {
+ Console.WriteLine("Caught an argument exception");
+ }
+ return 1;
+ #endregion
+ }
+
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/OutVariableDeclarations.cs b/csharp7/ExploreCsharpSeven/OutVariableDeclarations.cs
new file mode 100644
index 0000000..f883fb4
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/OutVariableDeclarations.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Linq;
+
+namespace ExploreCsharpSeven
+{
+ static class OutVariableDeclarations
+ {
+ public static int DeclareAtUse()
+ {
+ #region OutVariableDeclarations
+ var input = "1234";
+ if (int.TryParse(input, out int result))
+ Console.WriteLine(result);
+ else
+ Console.WriteLine("Could not parse input");
+ #endregion
+ return 0;
+ }
+
+ public static int ExploreScope()
+ {
+ #region OutVariableDeclarationScope
+ var input = "1234";
+ if (!int.TryParse(input, out int result))
+ {
+ Console.WriteLine("Could not parse input");
+ return 1;
+ }
+ Console.WriteLine(result);
+ #endregion
+ return 0;
+ }
+
+ public static int OutVarQuery()
+ {
+ #region DeclareOutQueryVariable
+ string[] input = { "1", "2", "3", "4", "five", "6", "7" };
+ var numbers = from s in input
+ select (success: int.TryParse(s, out int result), result);
+ foreach (var item in numbers)
+ Console.WriteLine($"{(item.success ? "Success result is: " : "Failed to parse")}\t{(item.success ? item.result.ToString() : string.Empty)}");
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/Program.cs b/csharp7/ExploreCsharpSeven/Program.cs
new file mode 100644
index 0000000..b69bc5f
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/Program.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Threading.Tasks;
+
+namespace ExploreCsharpSeven
+{
+ public class Program
+ {
+ public static int Main(string? region = null,
+ string? session = null,
+ string? package = null,
+ string? project = null,
+ string[]? args = null)
+ {
+ return region switch
+ {
+ "OutVariableDeclarations" => OutVariableDeclarations.DeclareAtUse(),
+ "OutVariableDeclarationScope" => OutVariableDeclarations.ExploreScope(),
+ "TupleDeclarations" => TupleUses.TupleDeclarations(),
+ "DeclareNamesOnTuple" => TupleUses.DeclareTupleVariable(),
+ "TupleReturningMethod" => TupleUses.TupleMinMax(),
+ "IsTypePattern" => IsExpressions.ExploreIsPattern(),
+ "TestTypeWithSwitch" => SwitchPatterns.CallTestType(),
+ "SwitchTypePattern" => SwitchPatterns.CallTestType(),
+ "RefFindMethod" => RefLocalsAndReturns.TestRefFind(),
+ "RefTestCode" => RefLocalsAndReturns.TestRefFind(),
+ "LocalFunctionFactorial" => LocalFunctions.TestLocalFactorial(),
+ "LocalFunctionFactorialTest" => LocalFunctions.TestLocalFactorial(),
+ "LocalFuntionIteratorMethod" => LocalFunctions.TestSubset(),
+ "LocalFunctionIteratorWithLocal" => LocalFunctions.TestSubset(),
+ "LocalFunctionsIteratorTest" => LocalFunctions.TestSubset(),
+ "PointStructure" => InReadonly.ModifyTheOrigin(),
+ "UsePointstructure" => InReadonly.ModifyTheOrigin(),
+ "ReadOnlyPoint" => ReadonlyStruct.ModifyTheOrigin(),
+ "TestReadOnlyPoint" => ReadonlyStruct.ModifyTheOrigin(),
+ "GenericSwitchTypePattern" => GenericPatterns.CallTestType(),
+ "GenericTestTypeWithSwitch" => GenericPatterns.CallTestType(),
+ "InferMemberNames" => TupleUses.InferredTupleNames(),
+ "DeclareOutQueryVariable" => OutVariableDeclarations.OutVarQuery(),
+ "DeclareEnumConstraint" => GenericConstraints.TestEnumNamedValues(),
+ "DeclareEnum" => GenericConstraints.TestEnumNamedValues(),
+ "TestMapEnumValues" => GenericConstraints.TestEnumNamedValues(),
+ _ => RunAll()
+ };
+ }
+
+ public static int RunAll()
+ {
+ OutVariableDeclarations.DeclareAtUse();
+ OutVariableDeclarations.ExploreScope();
+ TupleUses.TupleDeclarations();
+ TupleUses.DeclareTupleVariable();
+ TupleUses.TupleMinMax();
+ IsExpressions.ExploreIsPattern();
+ SwitchPatterns.CallTestType();
+ RefLocalsAndReturns.TestRefFind();
+ LocalFunctions.TestLocalFactorial();
+ LocalFunctions.TestSubset();
+ InReadonly.ModifyTheOrigin();
+ ReadonlyStruct.ModifyTheOrigin();
+ GenericPatterns.CallTestType();
+ TupleUses.InferredTupleNames();
+ OutVariableDeclarations.OutVarQuery();
+ GenericConstraints.TestEnumNamedValues();
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/ReadonlyStruct.cs b/csharp7/ExploreCsharpSeven/ReadonlyStruct.cs
new file mode 100644
index 0000000..51da118
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/ReadonlyStruct.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace ExploreCsharpSeven
+{
+
+ static class ReadonlyStruct
+ {
+ #region ReadOnlyPoint
+ public struct Point3D
+ {
+ private static Point3D origin = new Point3D(0, 0, 0);
+
+ public static ref readonly Point3D Origin => ref origin;
+
+ public double X { get; }
+ public double Y { get; }
+ public double Z { get; }
+
+ private double? distance;
+
+ public Point3D(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ distance = null;
+ }
+
+ public double ComputeDistance()
+ {
+ if (!distance.HasValue)
+ distance = Math.Sqrt(X * X + Y * Y + Z * Z);
+ return distance.Value;
+ }
+
+ public static Point3D Translate(in Point3D source, double dX, double dY, double dZ) =>
+ new Point3D(source.X + dX, source.Y + dY, source.Z + dZ);
+
+ public override string ToString()
+ => $"({X}, {Y}, {Z})";
+ }
+ #endregion
+
+ public static int ModifyTheOrigin()
+ {
+ #region TestReadOnlyPoint
+ ref readonly var start = ref Point3D.Origin;
+ Console.WriteLine($"Start at the origin: {start}");
+
+ // Move the start:
+ var location = Point3D.Translate(in start, 5, 5, 5);
+ Console.WriteLine($"Translate by (5,5,5): {location}");
+
+ Console.WriteLine($"Distance to origin is {location.ComputeDistance()}");
+
+ Console.WriteLine($"Check the origin again: {Point3D.Origin}");
+ #endregion
+ return 0;
+ }
+
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/RefLocalsAndReturns.cs b/csharp7/ExploreCsharpSeven/RefLocalsAndReturns.cs
new file mode 100644
index 0000000..cdb08e9
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/RefLocalsAndReturns.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace ExploreCsharpSeven
+{
+ static class RefLocalsAndReturns
+ {
+ #region RefFindMethod
+ public static (int i, int j) Find(int[,] matrix, Func predicate)
+ {
+ for (int i = 0; i < matrix.GetLength(0); i++)
+ for (int j = 0; j < matrix.GetLength(1); j++)
+ if (predicate(matrix[i, j]))
+ return (i, j);
+ return (-1, -1); // Not found
+ }
+ #endregion
+
+ public static int TestRefFind()
+ {
+ #region RefTestCode
+ int[,] sourceMatrix = new int[10, 10];
+ for (int x = 0; x < 10; x++)
+ for (int y = 0; y < 10; y++)
+ sourceMatrix[x, y] = x * 10 + y;
+
+ var indices = Find(sourceMatrix, (val) => val == 42);
+ Console.WriteLine(indices);
+ sourceMatrix[indices.i, indices.j] = 24;
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/SwitchPatterns.cs b/csharp7/ExploreCsharpSeven/SwitchPatterns.cs
new file mode 100644
index 0000000..29cef0a
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/SwitchPatterns.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace ExploreCsharpSeven
+{
+ static class SwitchPatterns
+ {
+ #region SwitchTypePattern
+ public static void TestType(object obj)
+ {
+ switch (obj)
+ {
+ case int i:
+ Console.WriteLine($"The object is an integer: {i}");
+ break;
+ case null:
+ Console.WriteLine($"The object is null");
+ break;
+ default:
+ Console.WriteLine($"The object is some other type");
+ break;
+ }
+ }
+ #endregion
+
+ public static int CallTestType()
+ {
+ #region TestTypeWithSwitch
+ TestType(5);
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/ExploreCsharpSeven/TupleUses.cs b/csharp7/ExploreCsharpSeven/TupleUses.cs
new file mode 100644
index 0000000..eb8413a
--- /dev/null
+++ b/csharp7/ExploreCsharpSeven/TupleUses.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+
+namespace ExploreCsharpSeven
+{
+ static class TupleUses
+ {
+ public static int TupleDeclarations()
+ {
+ #region TupleDeclarations
+ (string Alpha, string Beta) namedLetters = ("a", "b");
+ Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");
+ #endregion
+ return 0;
+ }
+
+ public static int DeclareTupleVariable()
+ {
+ #region DeclareNamesOnTuple
+ var alphabetStart = (Alpha: "a", Beta: "b");
+ Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");
+ #endregion
+ return 0;
+ }
+
+ public static int InferredTupleNames()
+ {
+ #region InferMemberNames
+ int count = 5;
+ string label = "Colors used in the map";
+ var pair = (count, label); // element names are "count" and "label"
+ Console.WriteLine(pair.count);
+ Console.WriteLine(pair.label);
+ #endregion
+ return 0;
+ }
+
+ public static int TupleMinMax()
+ {
+ #region TupleReturningMethod
+ (int Max, int Min) Range(IEnumerable sequence)
+ {
+ int Min = int.MaxValue;
+ int Max = int.MinValue;
+ foreach (var n in sequence)
+ {
+ Min = (n < Min) ? n : Min;
+ Max = (n > Max) ? n : Max;
+ }
+ return (Max, Min);
+ }
+
+ var numbers = new int[] { 1, 2, 3, 5, 8, 13, 21, 34, 55 };
+ var range = Range(numbers);
+ Console.WriteLine(range);
+ #endregion
+ return 0;
+ }
+ }
+}
diff --git a/csharp7/declare-tuples.md b/csharp7/declare-tuples.md
new file mode 100644
index 0000000..41b9215
--- /dev/null
+++ b/csharp7/declare-tuples.md
@@ -0,0 +1,48 @@
+# Tuples create light-weight data structures
+Tuples are lightweight data structures that contain multiple fields to represent the data members. The fields are not validated, and you cannot define your own methods.
+
+> NOTE:
+> Tuples were available before C# 7.0, but they were inefficient and had no language support. This meant that tuple elements could only be referenced as `Item1`, `Item2` and so on. C# 7.0 introduces language support for tuples, which enables semantic names for the fields of a tuple using new more efficient tuple types.
+
+You can create a tuple by assigning a value to each named member:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/TupleUses.cs --region TupleDeclarations
+```
+
+The `namedLetters` tuple contains fields referred to as `Alpha` and `Beta`. Those names exist only at compile time and are not preserved at runtime (when inspecting the tuple using reflection, for example).
+
+In a tuple assignment, you can also specify the names of the fields on the right-hand side of the assignment:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/TupleUses.cs --region DeclareNamesOnTuple
+```
+
+If you don't specify any names for the tuple members, the member names are inferred from the variable names on the right side of any initialization:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/TupleUses.cs --region InferMemberNames
+```
+
+You can specify names for the fields on both the left and right-hand side of the assignment. In that case, the variable uses the names on the left side of the assignment.
+
+Tuples are most useful as return types for `private` and `internal` methods. Tuples provide a simple syntax for those methods to return multiple discrete values. Creating a tuple is more efficient and more productive that creating a class or struct. It has a simpler, lightweight syntax to define a data structure that carries more than one value. The example method below returns the minimum and maximum values found in a sequence of integers. Try the following code:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/TupleUses.cs --region TupleReturningMethod
+```
+
+There may be times when you want to unpackage the members of a tuple that were returned from a method. You can do that by declaring separate variables for each of the values in the tuple. This is called *deconstructing* the tuple. Add the following code in your browser to try it:
+
+```csharp
+(int max, int min) = Range(numbers);
+Console.WriteLine(max);
+Console.WriteLine(min);
+```
+
+As you work with tuples, you'll often find that you don't use all of the members of a tuple result. When that happens, you can discard one or more of the returned values by using `_` in place of a variable. Try the following code yourself:
+
+```csharp
+(int maxValue, _) = Range(numbers);
+Console.WriteLine(max);
+```
+
+You can explore more in the [tuples article](https://docs.microsoft.com/dotnet/csharp/tuples) on docs.microsoft.com.
+
+#### Next: [out variable declarations »](./out-variable-declaration.md) Previous: [Generic types and pattern matching «](./out-variable-declaration.md) Home: [Home](readme.md)
diff --git a/csharp7/generic-constraints.md b/csharp7/generic-constraints.md
new file mode 100644
index 0000000..b5757c5
--- /dev/null
+++ b/csharp7/generic-constraints.md
@@ -0,0 +1,24 @@
+# Enhanced generic constraints
+
+some of the restrictions on generic constraints have been removed. You can now specify the type `System.Enum` or `System.Delegate` as base class constraints for a type parameter.
+
+You can also use the new `unmanaged` constraint, to specify that a type parameter must be an `unmanaged` type. An `unmanaged` type is a type that isn't a reference type and doesn't contain any reference type at any level of nesting.
+
+Consider the following generic method that builds a dictionary of all the values in an enum mapped to the string representations:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/GenericConstraints.cs --region DeclareEnumConstraint --session Generics
+```
+
+Next, declare an `enum` type:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/GenericConstraints.cs --region DeclareEnum --session Generics
+```
+
+Finally, test how it works:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/GenericConstraints.cs --region TestMapEnumValues --session Generics
+```
+
+Modify the `enum` values, or the method declaration or test code to experiment on your own.
+
+#### Previous: [Local functions «](./local-functions.md) Home: [Home](readme.md)
diff --git a/csharp7/generic-patterns.md b/csharp7/generic-patterns.md
new file mode 100644
index 0000000..bd05594
--- /dev/null
+++ b/csharp7/generic-patterns.md
@@ -0,0 +1,21 @@
+# Pattern matching on generic type parameters
+
+Looking at the `TestType` method on the previous page, you may be concerned about runtime type checking and possible boxing and unboxing concerns. Starting with C# 7.1, you can alleviate those concerns using generics.
+
+Beginning with C# 7.1, the pattern expression for is and the switch type pattern may have the type of a generic type parameter. This can be most useful when checking types that may be either struct or class types, and you want to avoid boxing.
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/GenericPatterns.cs --region GenericSwitchTypePattern --session GenericSwitchPatterns
+```
+
+Modify the declaration of `TestType` so it is a generic method:
+
+```csharp
+public static void TestType(T obj)
+```
+
+The test code follows.
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/GenericPatterns.cs --region GenericTestTypeWithSwitch --session GenericSwitchPatterns
+```
+
+#### Next: [declare tuples »](./declare-tuples.md) Previous: [Pattern matching switch expressions «](./switch-patterns.md) Home: [Home](readme.md)
diff --git a/csharp7/in-ref-readonly.md b/csharp7/in-ref-readonly.md
new file mode 100644
index 0000000..c6c0393
--- /dev/null
+++ b/csharp7/in-ref-readonly.md
@@ -0,0 +1,41 @@
+# Use ref readonly return statements for large structures
+
+The previous example showed one scenario for using `ref` variables for return values and local variables: You intended to pass by reference so that callers could modify the returned value. Another common scenario is to use pass-by-reference to avoid copying larger structures. Consider this `Point3D` structure:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/InReadonly.cs --region PointStructure --session InReadonly
+```
+
+Imagine that this structure is used in an application that creates millions of points, and performs a variety of computations on those points. The size of the `Point3D` structure means the cost of copying those structures is likely larger than the cost of working with references to them. Let's make some modifications to this class to pass instances by references. You'll learn how to do that safely, and enable optimizations from the compiler.
+
+Start by changing the `Origin` property to return a reference to the origin:
+
+```csharp
+public static ref Point3D Origin => ref origin;
+```
+
+To achieve any performance benefits from this change, modify the code below to declare `start` as a `ref` variable and see what happens:
+
+```csharp
+ref var start = ref Point3D.Origin;
+```
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/InReadonly.cs --region UsePointstructure --session InReadonly
+```
+
+You can prevent this kind of coding error by declaring the `Origin` property to return a `ref readonly` reference:
+
+```csharp
+public static ref readonly Point3D Origin => ref origin;
+```
+
+The compiler generates an error on the declaration of `start`. Add the `readonly` modifier after `ref` to fix it. That moves the error later where the code modifies `start`. Introduce a new variable instead of modifying `start`.
+
+These two changes show how adding the `readonly` modifier to `ref` variables and returns prevent unintended modifications. There are still changes you can make that enable the compiler to perform more optimizations. The `Translate` method could take its first input as a `ref` argument, but you don't want to allow modifications. Instead, use the `in` modifier to disallow any changes to the point or its members:
+
+```csharp
+public static Point3D Translate(in Point3D source, double dX, double dY, double dZ)
+```
+
+The primary motivation for adding these features in your code is performance. If you find that copying structures has a negative impact on your application, consider using pass-by-reference and readonly references to minimize the copies.
+
+#### Next: [readonly structs »](./readonly-struct.md) Previous: [From values to ref «](./use-ref-arguments.md) Home: [Home](readme.md)
diff --git a/csharp7/is-expressions.md b/csharp7/is-expressions.md
new file mode 100644
index 0000000..0f54f39
--- /dev/null
+++ b/csharp7/is-expressions.md
@@ -0,0 +1,35 @@
+# Use the type pattern with the is expression
+
+The `is` pattern expression extends the familiar `is` operator to query an object beyond its type.
+
+Try the following code:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/IsExpressions.cs --region IsTypePattern
+```
+
+Change the variable declaration to a string instead:
+
+```csharp
+object count = "5";
+```
+
+Now, the `is` expression is false, so the `else` branch is executed. Try to change `count` to `number` in the else branch:
+
+```csharp
+Console.WriteLine($"{number} is not an integer");
+```
+
+That change won't compile because `number` isn't assigned in the `else` branch. It's only assigned in the `true` branch of the `if` statement.
+
+In addition to the type pattern, you can use the constant pattern with the `is` statement. Add the following lines before the first `if` statement:
+
+```csharp
+if (count is 0)
+ Console.WriteLine("count is zero");
+```
+
+Modify the declaration of `count` to try different values.
+
+The `is` expression type pattern is useful when you have a small number of types to test against. Often, you may need to test multiple types. That requires the pattern matching `switch` statement.
+
+#### Next: [Pattern matching with switch »](./switch-patterns.md) Previous: [Readonly struct types «](./readonly-struct.md) Home: [Home](readme.md)
diff --git a/csharp7/local-functions.md b/csharp7/local-functions.md
new file mode 100644
index 0000000..5b7ddbe
--- /dev/null
+++ b/csharp7/local-functions.md
@@ -0,0 +1,21 @@
+# Minimize access to code with local functions
+
+You can now declare local functions that are nested inside other functions. This enables you to minimize the visibility of these functions. There are three obvious use cases for local functions:
+
+- Recursive functions.
+- Iterator methods.
+- Asynchronous methods.
+
+Let's start with recursive methods. Try the following code to calculate `6!` (factorial):
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/LocalFunctions.cs --region LocalFunctionFactorial --session Factorial
+```
+
+Use this block to try it with different values:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/LocalFunctions.cs --region LocalFunctionFactorialTest --session Factorial
+```
+
+Local functions are a great way to implement recursive algorithms. Other common uses are for public iterator methods and public async methods. Both types of methods generate code that reports errors later than programmers might expect. In the case of iterator methods, any exceptions are observed only when calling code that enumerates the returned sequence. In the case of async methods, any exceptions are only observed when the returned `Task` is awaited.
+
+#### Next [Local iterator meethods »](./local-iterator-methods.md) Previous: [out variable initializers «](./out-variable-declaration.md) Home: [Home](readme.md)
diff --git a/csharp7/local-iterator-methods.md b/csharp7/local-iterator-methods.md
new file mode 100644
index 0000000..80f009e
--- /dev/null
+++ b/csharp7/local-iterator-methods.md
@@ -0,0 +1,23 @@
+# Local iterator methods
+
+Iterator methods are easier to explore in this environment, so let's use those in this exploration. The following iterator method returns a sequence of letters from a starting letter to an ending letter:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/LocalFunctions.cs --region LocalFuntionIteratorMethod --session IteratorMethod
+```
+
+Try the following test code. It makes some invalid calls to the iterator method. Note when the exception is thrown:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/LocalFunctions.cs --region LocalFunctionsIteratorTest --session IteratorMethod
+```
+
+The exception is thrown when the code begins iterating the second result set. The code that iterates the first result set has already run. This sample is both small and doesn't change any data structures, so it's harmless and easy to fix. But, in a larger program, where the two iterator objects may be created in different child methods the root cause could be hard to find. If the first iterator method changed data state, it could even cause data corruption. You'd prefer the exception was thrown immediately, before any work is done. You can refactor the code so that the public method validates all arguments, and a local function performs the enumeration. Modify the preceding test code to call `AlphabetSubsetLocal` to observe the differences:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/LocalFunctions.cs --region LocalFunctionIteratorWithLocal --session IteratorMethod
+```
+
+The preceding version makes it clear that the local method is referenced only in the context of the outer method. The rules for local functions also ensure that a developer can't accidentally call the local function from another location in the class and bypass the argument validation.
+
+The same technique can be employed with `async` methods to ensure that exceptions arising from argument validation are thrown before the asynchronous
+work begins.
+
+#### Next [New generic constraints »](./generic-constraints.md) Previous: [Local functions «](./local-functions.md) Home: [Home](readme.md)
diff --git a/csharp7/out-variable-declaration.md b/csharp7/out-variable-declaration.md
new file mode 100644
index 0000000..03bbe11
--- /dev/null
+++ b/csharp7/out-variable-declaration.md
@@ -0,0 +1,31 @@
+# Out variable declarations at the assignment location
+
+One technique to ensure references are never set to null is to ensure every local variable of a reference type is initialized when it is declared. This is often referred to as *non-null by construction*. That previously wasn't easy for variables you intend to initialize by passing them to methods as `out` parameters. Starting with C# 7.0, you can declare `out` variables in the argument list of a method call, rather than writing a separate declaration statement. Try the following code:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/OutVariableDeclarations.cs --region OutVariableDeclarations
+```
+
+You can change the `int` declaration to a `var` declaration. Change the declaration to the following code:
+
+```csharp
+if (int.TryParse(input, out var result))
+```
+
+The new syntax provides two important advantages over the existing syntax:
+
+* The code is easier to read.
+ - You declare the out variable where you use it, not on another line above.
+* No need to assign an initial value.
+ - By declaring the `out` variable where it is used in a method call, you can't accidentally use it before it is correctly assigned.
+
+The declared variable's scope is the scope enclosing the `if` statement. This allows you to use the variable afterwards. Modify the last `if` block as shown in the following snippet.
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/OutVariableDeclarations.cs --region OutVariableDeclarationScope
+```
+
+In C# 7.1, out variable declarations have been extended to include field initializers, property initializers, constructor initializers, and query clauses. It enables code such as the following example:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/OutVariableDeclarations.cs --region DeclareOutQueryVariable
+```
+
+#### Next: [Local functions »](./local-functions.md) Previous: [Declare lightweight types with tuples «](./declare-tuples.md) Home: [Home](readme.md)
diff --git a/csharp7/readme.md b/csharp7/readme.md
new file mode 100644
index 0000000..b76d521
--- /dev/null
+++ b/csharp7/readme.md
@@ -0,0 +1,58 @@
+# What's new in C# 7.0 thru C# 7.3 - exploration
+
+This exploration enables you to experiment with the features that have been released in C# 7.0, and the following point releases through C# 7.3. You can try the code in the samples, modify it, and see the effects of using the new features in a variety of scenarios. Some of the features added in the point releases are enhancements and improvements to features first available in C# 7.0. This exploration is organized around the themes across all the C# 7.x features, rather than by release. As you explore each area, enhancements that are available in later point releases are noted.
+
+The themes of these releases are:
+
+## Better control over allocations and copies
+
+The .NET environment manages memory automatically. However, some scenarios require developers to take more control over the memory footprint of their application. This has meant developers needed to write unsafe code. The goal of these features is to enable developers to achieve the performance of unsafe code while writing verifiably safe code. The features that enable these gains are:
+
+- [ref locals and returns](./ref-locals-returns.md)
+- [in and ref readonly](./in-ref-readonly.md)
+- [readonly struct](./readonly-struct.md)
+- [ref struct](./readonly-struct#ref-struct-types.md)
+
+## Pattern matching
+
+Modern applications are often a collection of different programs that execute on multiple machines and platforms. That separates data from the code that consumes the data. A strict object oriented approach doesn't work as well in these systems. **Pattern matching** enables new ways to examine data using its type, shape, or values. The features added for pattern matching are:
+
+- [pattern matching is expressions](./is-expressions.md)
+- [pattern matching with switch](./switch-patterns.md)
+- [pattern matching on generic type elements](./generic-patterns.md)
+
+## Tuple data types
+
+Tuples combine both of the previous themes: They are lightweight value types that contain multiple members:
+
+- [Create lightweight data structures using tuples](./declare-tuples.md)
+
+## Preparing for nullable reference types
+
+Features were added to C# 7.x that make it easier to adopt nullable reference types in C# 8. These features reduce the locations where you must declare a variable and initialize it later.
+
+- [Declare out variables when assigned](./out-variable-declaration.md)
+
+Many of these use unsafe code, which aren't available in the local `dotnet try` environment. Learn more about them on docs.microsoft.com:
+
+- [fixed fields without pinning](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-3)
+- [stackalloc array initializers](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-3#stackalloc-arrays-support-initializers)
+- [Conditional ref expressions](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-2#conditional-ref-expressions)
+
+## Improve code organization and readability
+
+Other features improve your ability to write clear code in a variety of scenarios:
+
+- [local functions](local-functions.md)
+- [new generic constraints ](generic-constraints.md)
+
+Two other features aren't in this tutorial. Learn more about them on docs.microsoft.com:
+
+- [attributes on backing fields of properties](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-3#attach-attributes-to-the-backing-fields-for-auto-implemented-properties)
+- [Async Main methods](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-1#async-main)
+- [default literal expressions](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-1#default-literal-expressions)
+- [Leading underscores in numeric literals](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-7-2#leading-underscores-in-numeric-literals)
+
+You can try these scenarios and features in C# 7.x by stepping through the different sections of this tutorial. Or, you can select any of the preceding links to go to the feature you want to explore first.
+
+## Next: [ref locals and returns »](./ref-locals-returns.md)
diff --git a/csharp7/readonly-struct.md b/csharp7/readonly-struct.md
new file mode 100644
index 0000000..60308fc
--- /dev/null
+++ b/csharp7/readonly-struct.md
@@ -0,0 +1,30 @@
+# Declare readonly structs for immutable value types
+
+The intent of the `Point3D` structure is that it is immutable. It's public interface appears to be immutable. However, the compiler can't discern that intent, and that has implications. Most importantly, the compiler can't help you enforce that design intent. A human reader can look at the code and determine that you intend it to be immutable, but that's only a convention. In addition, the compiler must assume that a `Point3D` is not immutable. That means the compiler will create a *defensive copy* when a readonly reference to a `Point3D` accesses a member. Let's look at the `Point3D` structure one more time:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/ReadonlyStruct.cs --region ReadOnlyPoint --session ReadOnlyStruct
+```
+
+Change the declaration of `Point3D` by adding the `readonly` modifier:
+
+```csharp
+public readonly struct Point3D
+```
+
+This has two advantages. First, it exposes any accidental modifications of the struct. You can see this in the error in `ComputeDistance`. Refactor that method, and remove the `distance` member field so that `Point3D` struct us completely immutuble. Second, the compiler can take advantage of the knowledge that `Point3D` is immutable to skip any defensive copies.
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/ReadonlyStruct.cs --region TestReadOnlyPoint --session ReadOnlyStruct
+```
+
+Declaring a struct using the readonly modifier informs the compiler that your intent is to create an immutable type. The compiler enforces that design decision with the following rules:
+
+- All field members must be readonly
+- All properties must be read-only, including auto-implemented properties.
+
+These two rules are sufficient to ensure that no member of a readonly struct modifies the state of that struct. The struct is immutable. Declare your structs as `readonly` whenever your design intent is to create an immutable value type. Any performance improvements are an added benefit. The readonly struct clearly expresses your design intent.
+
+## ref struct types
+
+A related language feature is the ability to declare a value type that must be constrained to a single stack frame. This restriction enables the compiler to make several optimizations. The primary motivation for this feature was `Span` and related structures. You'll achieve performance improvements from these enhancements by using new and updated .NET APIs that make use of the `Span` type. You can combine these features to create `ref readonly struct` types, such as `ReadonlySpan`.
+
+#### Next: [Pattern matching is expressions »](./is-expressions.md) Previous: [in arguments and ref readonly returns «](./in-ref-readonly.md) Home: [Home](readme.md)
diff --git a/csharp7/ref-locals-returns.md b/csharp7/ref-locals-returns.md
new file mode 100644
index 0000000..78cf794
--- /dev/null
+++ b/csharp7/ref-locals-returns.md
@@ -0,0 +1,19 @@
+# Optimize memory storage using ref locals and returns
+
+This feature enables algorithms that use and return references to variables defined elsewhere. These features can be used to avoid copying values when passing them to methods, or returning them from methods. By passing and returning references to storage, copies are minimized.
+
+One example is with large matrices and finding a single location with certain characteristics. Let's start by examining a method that returns the two indices that reference a single location in the matrix:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/RefLocalsAndReturns.cs --region RefFindMethod --session RefLocals
+```
+
+You can test this method using the following code:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/RefLocalsAndReturns.cs --region RefTestCode --session RefLocals
+```
+
+This `Find` method returns the indices to the item in the matrix. That leads callers to write code that uses those indices to dereference the matrix and modify a single element. You'd rather write a method that returns a *reference* to the element of the matrix that you want to change.
+
+Let's walk through a series of changes to demonstrate the ref local feature and show how to create a method that returns a reference to internal storage. Along the way, you'll learn the rules of the ref return and ref local feature that protect you from accidentally misusing it.
+
+#### Next: [From values to references »](./use-ref-arguments.md) Home: [Home](readme.md)
diff --git a/csharp7/switch-patterns.md b/csharp7/switch-patterns.md
new file mode 100644
index 0000000..c5cd565
--- /dev/null
+++ b/csharp7/switch-patterns.md
@@ -0,0 +1,84 @@
+# Pattern matching in the switch statement
+
+The *match expression* has a familiar syntax, based on the `switch` statement already part of the C# language. Let's start with a small sample based on the `is` expression syntax you explored on the previous page:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/SwitchPatterns.cs --region SwitchTypePattern --session SwitchPatterns
+```
+
+You can try that code using the following method call:
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/SwitchPatterns.cs --region TestTypeWithSwitch --session SwitchPatterns
+```
+
+The preceding code checks for an `int` or `null`. Every other type reached the default case. Add the following two lines to verify the behavior:
+
+```csharp
+long longValue = 12;
+TestType(longValue);
+```
+
+The `switch` expression will convert a nullable type to its corresponding type. Add the following to verify:
+
+```csharp
+int? answer = 42;
+TestType(answer);
+```
+
+You can add any number of other type pattern expressions to the switch statements. Add these before the `null` case:
+
+```csharp
+case long l:
+ Console.WriteLine($"The object is a long: {l}");
+ break;
+case double d:
+ Console.WriteLine($"The object is a double: {d}");
+ break;
+case string s when s.StartsWith("This"):
+ Console.WriteLine($"This was a string that started with the word 'This': {s}");
+ break;
+case string s:
+ Console.WriteLine($"The object is a string: {s}");
+ break;
+```
+
+Make sure these work by adding the following tests:
+
+```csharp
+double pi = 3.14;
+TestType(pi);
+string sum = "12";
+TestType(sum);
+answer = null;
+TestType(answer);
+```
+
+The match expressions also support constants. This can save time by factoring out simple cases:
+
+```csharp
+case 5:
+ Console.WriteLine("The object is 5");
+ break;
+```
+
+You must add the preceding case *before* the `case int:` expression. If you add it after that case, the compiler warns you that it has already been handled by a previous case.
+
+You can add a `when` clause to any pattern case so that you can test other conditions beyond a type or a constant value. Try it by adding the following case above the general `string` case:
+
+```csharp
+case string s when s.StartsWith("This"):
+ Console.WriteLine($"This was a string that started with the word 'This': {s}");
+ break;
+```
+
+Test it with something like the following code:
+
+```csharp
+string message = "This is a longer message";
+TestType(message);
+```
+
+The new syntax for pattern matching expressions makes it easier to create dispatch algorithms using a clear and concise syntax based on an object's type or other properties. Pattern matching expressions enable these constructs on data types that are unrelated by inheritance.
+
+You can learn more about pattern matching in the article dedicated to [pattern matching in C#](../../pattern-matching.md).
+
+#### Next: [Generic type expressions »](./generic-patterns.md) Previous: [Pattern matching is expressions «](./is-expressions.md) Home: [Home](readme.md)
diff --git a/csharp7/use-ref-arguments.md b/csharp7/use-ref-arguments.md
new file mode 100644
index 0000000..5d61f56
--- /dev/null
+++ b/csharp7/use-ref-arguments.md
@@ -0,0 +1,58 @@
+# Use ref instead of values
+
+Let's start by modifying the `Find` method to return a reference to an element in matrix. Change the return type of the `Find` method from `(int i, int j)` to `ref int`.
+
+After that change, you'll need to modify both return statements. The first should return the element instead of the indices:
+
+```csharp
+return matrix[i,j];
+```
+
+Note this doesn't compile. You need to add the `ef` modifier to the return statement. This makes it clear that the code returns a reference, not a value.
+
+```csharp
+return ref matrix[i,j];
+```
+
+The second `return` should throw an exception instead of returning invalid indices, because you can't return a reference to a "not found" element:
+
+```csharp
+throw new InvalidOperationException("Not found");
+```
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/RefLocalsAndReturns.cs --region RefFindMethod --session RefUpdates
+```
+
+The `Find` method now returns a reference to the found element. This introduces compiler errors in the code that tests this method. Replace the last three lines of the code below with the following code:
+
+```csharp
+var valItem = Find(sourceMatrix, (val) => val == 42);
+Console.WriteLine(valItem);
+valItem = 24;
+Console.WriteLine(sourceMatrix[4, 2]);
+```
+
+```cs --project ./ExploreCsharpSeven/ExploreCsharpSeven.csproj --source-file ./ExploreCsharpSeven/RefLocalsAndReturns.cs --region RefTestCode --session RefUpdates
+```
+
+Try this code. The value in `sourceMatrix` doesn't change. That's because `valItem` is not declared as a `ref` local variable. Because it's declared as a value, the return value is *copied*. Add the `ref` modifier before `var` in the declaration of `valItem`. That introces a new compiler error. Add the `ref` modifier before the `Find` method name to fix it:
+
+```csharp
+ref var valItem = ref Find(sourceMatrix, (val) => val == 42);
+```
+
+When first introduced, you couldn't reassign the reference that a `ref` local variable refers to. Beginning with 7.3, you can reassign a ref local variable. Add the following code to the bottom of the test code:
+
+```csharp
+valItem = Find(sourceMatrix, (val) => val == 16);
+```
+
+The C# language has three other rules that protect you from misusing the `ref` locals and returns:
+
+* You cannot assign a standard method return value to a `ref` local variable.
+* You cannot return a `ref` to a variable whose lifetime does not extend beyond the execution of the method.
+* `ref` locals and returns can't be used with async methods.
+
+The addition of ref locals and ref returns enable algorithms that are more efficient by avoiding copying values or performing dereferencing operations multiple times.
+
+#### Next: [in arguments and ref readonly returns »](./in-ref-readonly.md) Previous: [ref locals and returns «](./ref-locals-returns.md) Home: [Home](readme.md)