├── .gitattributes ├── .gitignore ├── CsharpSeven.sln ├── CsharpSeven ├── BinaryLiterals.cs ├── CsharpSeven.csproj ├── LocalFunctions.cs ├── OutVarDeclaration.cs ├── PatternMatching.cs ├── RefLocalAndRefReturn.cs ├── ThrowExceptions.cs ├── Tuples.cs └── ValueTask.cs └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Visual Studio Code 28 | .vscode/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | *.VC.db 87 | *.VC.VC.opendb 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | *.sap 94 | 95 | # TFS 2012 Local Workspace 96 | $tf/ 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | *.DotSettings.user 105 | 106 | # JustCode is a .NET coding add-in 107 | .JustCode 108 | 109 | # TeamCity is a build add-in 110 | _TeamCity* 111 | 112 | # DotCover is a Code Coverage Tool 113 | *.dotCover 114 | 115 | # NCrunch 116 | _NCrunch_* 117 | .*crunch*.local.xml 118 | nCrunchTemp_* 119 | 120 | # MightyMoose 121 | *.mm.* 122 | AutoTest.Net/ 123 | 124 | # Web workbench (sass) 125 | .sass-cache/ 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.[Pp]ublish.xml 145 | *.azurePubxml 146 | # TODO: Comment the next line if you want to checkin your web deploy settings 147 | # but database connection strings (with potential passwords) will be unencrypted 148 | #*.pubxml 149 | *.publishproj 150 | 151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 152 | # checkin your Azure Web App publish settings, but sensitive information contained 153 | # in these scripts will be unencrypted 154 | PublishScripts/ 155 | 156 | # NuGet Packages 157 | *.nupkg 158 | # The packages folder can be ignored because of Package Restore 159 | **/packages/* 160 | # except build/, which is used as an MSBuild target. 161 | !**/packages/build/ 162 | # Uncomment if necessary however generally it will be regenerated when needed 163 | #!**/packages/repositories.config 164 | # NuGet v3's project.json files produces more ignoreable files 165 | *.nuget.props 166 | *.nuget.targets 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Windows Store app package directories and files 177 | AppPackages/ 178 | BundleArtifacts/ 179 | Package.StoreAssociation.xml 180 | _pkginfo.txt 181 | 182 | # Visual Studio cache files 183 | # files ending in .cache can be ignored 184 | *.[Cc]ache 185 | # but keep track of directories ending in .cache 186 | !*.[Cc]ache/ 187 | 188 | # Others 189 | ClientBin/ 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.jfm 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | 258 | # CodeRush 259 | .cr/ 260 | 261 | # Python Tools for Visual Studio (PTVS) 262 | __pycache__/ 263 | *.pyc -------------------------------------------------------------------------------- /CsharpSeven.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.7 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpSeven", "CsharpSeven\CsharpSeven.csproj", "{10C5DE73-C40F-4019-AC48-0BBF6479A019}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {10C5DE73-C40F-4019-AC48-0BBF6479A019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {10C5DE73-C40F-4019-AC48-0BBF6479A019}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {10C5DE73-C40F-4019-AC48-0BBF6479A019}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {10C5DE73-C40F-4019-AC48-0BBF6479A019}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /CsharpSeven/BinaryLiterals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace CsharpSeven 5 | { 6 | public class BinaryLiterals 7 | { 8 | [Theory] 9 | [InlineData(0b001, 1)] 10 | [InlineData(0b010, 2)] 11 | [InlineData(0b011, 3)] 12 | [InlineData(0b100, 4)] 13 | [InlineData(0b101, 5)] 14 | [InlineData(0b110, 6)] 15 | [InlineData(0b111, 7)] 16 | public void Should_Declare_Int(int binLitteral, int normal) 17 | { 18 | Assert.Equal(binLitteral, normal); 19 | } 20 | 21 | [Theory] 22 | [InlineData(0b1, 1)] 23 | [InlineData(0b01, 1)] 24 | [InlineData(0b001, 1)] 25 | [InlineData(0b0001, 1)] 26 | [InlineData(0b00001, 1)] 27 | [InlineData(0b000001, 1)] 28 | [InlineData(0b0000001, 1)] 29 | [InlineData(0b00000001, 1)] 30 | public void Should_Not_Care_About_Higher_Bits_Zeroes(int binLitteral, int expected) 31 | { 32 | Assert.Equal(binLitteral, expected); 33 | } 34 | 35 | public void Should_Work_As_Enum_Value() 36 | { 37 | const DaysOfWeek day = DaysOfWeek.Friday; 38 | Assert.True(DaysOfWeek.Weekdays.HasFlag(day)); 39 | Assert.False(DaysOfWeek.Weekends.HasFlag(day)); 40 | } 41 | } 42 | 43 | [Flags] 44 | public enum DaysOfWeek 45 | { 46 | Monday = 0b00000001, 47 | Tuesday = 0b00000010, 48 | Wednesday = 0b00000100, 49 | Thursday = 0b00001000, 50 | Friday = 0b00010000, 51 | Saturday = 0b00100000, 52 | Sunday = 0b01000000, 53 | 54 | Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday, 55 | Weekends = Saturday | Sunday 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CsharpSeven/CsharpSeven.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp1.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CsharpSeven/LocalFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Xunit; 5 | 6 | namespace CsharpSeven 7 | { 8 | public class LocalFunctionsTests 9 | { 10 | [Fact] 11 | public void Works_For_String() 12 | { 13 | /* Setup */ 14 | const string name = "World"; 15 | 16 | /* Test */ 17 | var greeting = LocalFunctions.Greet(name); 18 | 19 | /* Assert */ 20 | Assert.Equal(greeting, "Hello, World!"); 21 | } 22 | 23 | [Fact] 24 | public async Task Work_With_Async_Await() 25 | { 26 | /* Setup */ 27 | const string name = "World"; 28 | 29 | /* Test */ 30 | var greeting = await LocalFunctions.GreetAsync(name); 31 | 32 | /* Assert */ 33 | Assert.Equal(greeting, "Hello, World!"); 34 | } 35 | 36 | [Fact] 37 | public void Work_With_Yielded_Enumerable() 38 | { 39 | /* Setup */ 40 | const string name = "World"; 41 | 42 | /* Test */ 43 | var greeting = LocalFunctions.YieldGreet(name); 44 | 45 | /* Assert */ 46 | Assert.Equal(greeting, "Hello, World!"); 47 | } 48 | 49 | [Fact] 50 | public void Works_With_Nested_Methods() 51 | { 52 | /* Setup */ 53 | const string name = "World"; 54 | 55 | /* Test */ 56 | var greeting = LocalFunctions.GreetNested(name); 57 | 58 | /* Assert */ 59 | Assert.Equal(greeting, "Hello, World!"); 60 | } 61 | 62 | [Fact] 63 | public void Works_With_Complex_Nested_Method() 64 | { 65 | /* Setup */ 66 | const string name = "World"; 67 | 68 | /* Test */ 69 | var greeting = LocalFunctions.GreetComplexNested(name); 70 | 71 | /* Assert */ 72 | Assert.Equal(greeting, "Hello, World!"); 73 | } 74 | } 75 | 76 | public class LocalFunctions 77 | { 78 | public const string HelloTemplate = "Hello, {0}!"; 79 | 80 | public static string Greet(string name) 81 | { 82 | var template = GetTemplate(); 83 | return string.Format(template, name); 84 | 85 | string GetTemplate() 86 | { 87 | return HelloTemplate; 88 | } 89 | } 90 | 91 | public static string GreetNested(string name) 92 | { 93 | var template = GetTemplate(); 94 | return string.Format(template, name); 95 | 96 | string GetTemplate() 97 | { 98 | return ReallyGetItNow(); 99 | 100 | string ReallyGetItNow() 101 | { 102 | return ReallyReallyReallyGetIt(); 103 | 104 | string ReallyReallyReallyGetIt() 105 | { 106 | return HelloTemplate; 107 | } 108 | } 109 | } 110 | } 111 | 112 | public static string GreetComplexNested(string name) 113 | { 114 | var template = GetTemplate(); 115 | return string.Format(template, name); 116 | 117 | string GetTemplate() 118 | { 119 | return GetFromSecondLevelLocal(); 120 | 121 | string GetFromSecondLevelLocal() 122 | { 123 | // Call to local method of outer scoop 124 | return GetFromFirstLevelLocal(); 125 | } 126 | } 127 | 128 | string GetFromFirstLevelLocal() 129 | { 130 | return HelloTemplate; 131 | } 132 | } 133 | 134 | public static async Task GreetAsync(string name) 135 | { 136 | var template = await GetTemplateAsync(); 137 | return string.Format(template, name); 138 | 139 | Task GetTemplateAsync() 140 | { 141 | return Task.FromResult(HelloTemplate); 142 | } 143 | } 144 | 145 | public static string YieldGreet(string name) 146 | { 147 | var template = string.Concat(GetTemplateCharacters()); 148 | return string.Format(template, name); 149 | 150 | IEnumerable GetTemplateCharacters() 151 | { 152 | foreach (var character in HelloTemplate) 153 | { 154 | yield return character; 155 | } 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /CsharpSeven/OutVarDeclaration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace CsharpSeven 7 | { 8 | public class OutVarDeclarationTests 9 | { 10 | [Fact] 11 | public void Works_With_Try_Parse() 12 | { 13 | /* Setup */ 14 | var guidAsString = Guid.NewGuid().ToString(); 15 | 16 | /* Test & Assert */ 17 | if (Guid.TryParse(guidAsString, out var parsed)) 18 | { 19 | Assert.NotEqual(parsed, Guid.Empty); 20 | } 21 | else 22 | { 23 | Assert.True(false, "Could not parse Guid"); 24 | } 25 | } 26 | 27 | [Fact] 28 | public void Works_With_Discard_Operator() 29 | { 30 | /* Setup */ 31 | var guidAsString = Guid.NewGuid().ToString(); 32 | 33 | /* Test */ 34 | var isGuid = Guid.TryParse(guidAsString, out _); 35 | 36 | /* Assert */ 37 | Assert.True(isGuid); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CsharpSeven/PatternMatching.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace CsharpSeven 7 | { 8 | public class PatternMatching 9 | { 10 | [Fact] 11 | public void Works_In_Switch_Cases() 12 | { 13 | Geometry geometry = new Square { Width = 5 }; 14 | 15 | switch (geometry) 16 | { 17 | case Rectangle r: 18 | Assert.True(false, $"Create square, got rectangle {r.Height} x {r.Width}."); 19 | break; 20 | case Square s: 21 | Assert.Equal(s.Width, 5); 22 | break; 23 | default: 24 | Assert.True(false); 25 | break; 26 | } 27 | } 28 | 29 | [Fact] 30 | public void Works_In_Conditional_Switch_Cases() 31 | { 32 | Geometry geometry = new Rectangle 33 | { 34 | Width = 5, 35 | Height = 5 36 | }; 37 | 38 | switch (geometry) 39 | { 40 | case Rectangle sq when sq.Width == sq.Height: 41 | Assert.True(true); 42 | break; 43 | default: 44 | Assert.True(false, "Should match condition above."); 45 | break; 46 | } 47 | } 48 | 49 | [Fact] 50 | public void Works_In_Var_Is_Type() 51 | { 52 | Geometry rectangle = new Rectangle {Height = 1, Width = 2}; 53 | if (rectangle is Square square) 54 | { 55 | Assert.False(true, $"This should not happen. Rectangle is not square {square.Width}x{square.Width}."); 56 | } 57 | 58 | if (rectangle is Rectangle r) 59 | { 60 | Assert.Equal(r.Width, 2); 61 | Assert.Equal(r.Height, 1); 62 | } 63 | } 64 | } 65 | 66 | internal class Geometry { } 67 | 68 | internal class Rectangle : Geometry 69 | { 70 | public int Width { get; set; } 71 | public int Height { get; set; } 72 | } 73 | 74 | class Square : Geometry 75 | { 76 | public int Width { get; set; } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CsharpSeven/RefLocalAndRefReturn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | using Microsoft.VisualBasic.CompilerServices; 6 | using Xunit; 7 | 8 | namespace CsharpSeven 9 | { 10 | public class RefLocalAndRefReturn 11 | { 12 | [Fact] 13 | public void Works_For_Value_Type_By_Ref() 14 | { 15 | /* Setup */ 16 | ref int GetLargets(ref int first, ref int second) 17 | { 18 | if (first > second) 19 | { 20 | return ref first; 21 | } 22 | return ref second; 23 | } 24 | 25 | var eleven = 11; 26 | var thirty = 30; 27 | 28 | /* Test */ 29 | ref var largestNumber = ref GetLargets(ref eleven, ref thirty); 30 | 31 | /* Assert */ 32 | Assert.Equal(largestNumber, thirty); 33 | 34 | largestNumber++; 35 | Assert.Equal(largestNumber, thirty); 36 | } 37 | 38 | [Fact] 39 | public void Works_For_Class_Members() 40 | { 41 | ref int Highest(Numbers numbers) 42 | { 43 | if (numbers.First > numbers.Second) 44 | { 45 | return ref numbers.First; 46 | } 47 | return ref numbers.Second; 48 | } 49 | 50 | /* Setup */ 51 | var twoByFour = new Numbers 52 | { 53 | First = 2, 54 | Second = 4 55 | }; 56 | 57 | /* Test */ 58 | ref var byRef = ref Highest(twoByFour); 59 | var byValue = Highest(twoByFour); 60 | 61 | /* Assert */ 62 | Assert.Equal(byRef, twoByFour.Second); 63 | Assert.Equal(byValue, twoByFour.Second); 64 | 65 | byRef++; 66 | Assert.Equal(byRef, twoByFour.Second); 67 | Assert.NotEqual(byValue, twoByFour.Second); 68 | } 69 | 70 | [Fact] 71 | public void Works_For_List_Members_With_Extension_Method() 72 | { 73 | /* Setup */ 74 | var numbers = new[] {1, 2, 3, 4, 5, 6, 7}; 75 | 76 | /* Test */ 77 | ref var highest = ref numbers.GetHighestValue(); 78 | 79 | /* Assert */ 80 | Assert.Equal(highest, 7); 81 | 82 | highest++; 83 | var highestFromArray = numbers.Max(); 84 | Assert.Equal(highestFromArray, 8); 85 | } 86 | } 87 | 88 | internal static class ListOfIntExtensions 89 | { 90 | public static ref int GetHighestValue(this int[] numbers) 91 | { 92 | if (numbers.Length == 0) 93 | { 94 | throw new ArgumentException(); 95 | } 96 | var highestIndex = 0; 97 | for (var index = 1; index < numbers.Length; index++) 98 | { 99 | if (numbers[highestIndex] < numbers[index]) 100 | { 101 | highestIndex = index; 102 | } 103 | } 104 | 105 | return ref numbers[highestIndex]; 106 | } 107 | } 108 | 109 | internal class Numbers 110 | { 111 | public int First; 112 | public int Second; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /CsharpSeven/ThrowExceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace CsharpSeven 5 | { 6 | public class ThrowExceptions 7 | { 8 | [Fact] 9 | public void Works_With_Null_Coalescing_Operator() 10 | { 11 | Assert.Throws(() => 12 | { 13 | string name = null; 14 | var theName = name ?? throw new Exception(); 15 | }); 16 | } 17 | 18 | [Fact] 19 | public void Works_With_Conditional_Operator() 20 | { 21 | Assert.Throws(() => 22 | { 23 | var id = string.Empty; 24 | var idAsGuid = Guid.TryParse(id, out var p) 25 | ? p : 26 | throw new Exception(); 27 | }); 28 | } 29 | 30 | [Fact] 31 | public void Works_With_Expression_Bodies() 32 | { 33 | void ThrowIt() => throw new Exception(); 34 | 35 | Assert.Throws(() => 36 | { 37 | ThrowIt(); 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CsharpSeven/Tuples.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace CsharpSeven 5 | { 6 | public class Tuples 7 | { 8 | [Fact] 9 | public void Works_For_Simple_Tuple() 10 | { 11 | (int Added, int Multiplied) Calculate(int first, int second) 12 | { 13 | return (first + second, first * second); 14 | } 15 | 16 | /* Setup */ 17 | const int four = 4; 18 | const int five = 5; 19 | 20 | /* Test */ 21 | var result = Calculate(four, five); 22 | 23 | /* Assert */ 24 | Assert.Equal(result.Added, 9); 25 | Assert.Equal(result.Multiplied, 20); 26 | } 27 | 28 | [Fact] 29 | public void Works_As_Class_Member() 30 | { 31 | /* Setup */ 32 | var person = new Person 33 | { 34 | FirstName = "Darth", 35 | LastName = "Vader" 36 | }; 37 | 38 | /* Test */ 39 | var fullName = person.FullName; 40 | 41 | /* Assert */ 42 | Assert.Equal(fullName.First, person.FirstName); 43 | Assert.Equal(fullName.Last, person.LastName); 44 | } 45 | 46 | [Fact] 47 | public void Should_Survive_Type_Casting() 48 | { 49 | /* Setup */ 50 | var person = new Person 51 | { 52 | FirstName = "Darth", 53 | LastName = "Vader" 54 | }; 55 | var tupple = person.FullName; 56 | var tuppleAsObj = tupple as object; 57 | 58 | /* Test */ 59 | var backAgain = (ValueTuple)tuppleAsObj; 60 | 61 | /* Assert */ 62 | Assert.Equal(backAgain.Item1, person.FirstName); 63 | Assert.Equal(backAgain.Item2, person.LastName); 64 | } 65 | 66 | [Fact] 67 | public void Works_With_Generic_Arguments() 68 | { 69 | (T1 FirstArgument, T2 SecondArgument) Create(T1 t1, T2 t2) 70 | { 71 | return (t1, t2); 72 | } 73 | 74 | /* Setup */ 75 | const int one = 1; 76 | const string hello = "hello"; 77 | /* Test */ 78 | var tupple = Create(one, hello); 79 | 80 | /* Assert */ 81 | Assert.Equal(tupple.FirstArgument, one); 82 | Assert.Equal(tupple.SecondArgument, hello); 83 | } 84 | 85 | [Fact] 86 | public void Can_Be_Deconstructed() 87 | { 88 | (int Added, int Multiplied) Calculate(int first, int second) 89 | { 90 | return (first + second, first * second); 91 | } 92 | 93 | /* Setup */ 94 | const int four = 4; 95 | const int five = 5; 96 | 97 | /* Test */ 98 | (var added, var multipled) = Calculate(four, five); 99 | 100 | /* Assert */ 101 | Assert.Equal(added, 9); 102 | Assert.Equal(multipled, 20); 103 | } 104 | 105 | 106 | [Fact] 107 | public void Can_Deconstruct_Objects() 108 | { 109 | /* Setup */ 110 | var person = new Person 111 | { 112 | FirstName = "Obi-Wan", 113 | LastName = "Kenobi" 114 | }; 115 | 116 | /* Test */ 117 | (var first, var last) = person; 118 | 119 | /* Assert */ 120 | Assert.Equal(first, person.FirstName); 121 | Assert.Equal(last, person.LastName); 122 | } 123 | 124 | [Fact] 125 | public void Can_Deconstruct_Objects_With_Discard_Operator() 126 | { 127 | /* Setup */ 128 | var person = new Person 129 | { 130 | FirstName = "Obi-Wan", 131 | LastName = "Kenobi" 132 | }; 133 | 134 | /* Test */ 135 | (var first, _) = person; 136 | 137 | /* Assert */ 138 | Assert.Equal(first, person.FirstName); 139 | } 140 | 141 | [Fact] 142 | public void Can_Deconstruct_From_Extension_Method() 143 | { 144 | /* Setup */ 145 | var xmas = new DateTime(2017, 12, 24); 146 | 147 | /* Test */ 148 | (var year, var month, var day) = xmas; 149 | 150 | /* Assert */ 151 | Assert.Equal(xmas.Year, year); 152 | Assert.Equal(xmas.Month, month); 153 | Assert.Equal(xmas.Day, day); 154 | } 155 | } 156 | 157 | internal class Person 158 | { 159 | public string FirstName { get; set; } 160 | public string LastName { get; set; } 161 | public (string First, string Last) FullName => (FirstName, LastName); 162 | 163 | public void Deconstruct(out string firstName, out string lastName) 164 | { 165 | firstName = FirstName; 166 | lastName = LastName; 167 | } 168 | } 169 | 170 | internal static class DateTimeDeconstructExtension 171 | { 172 | public static void Deconstruct(this DateTime datetime, out int year, out int month, out int day) 173 | { 174 | year = datetime.Year; 175 | month = datetime.Month; 176 | day = datetime.Day; 177 | } 178 | 179 | public static void Deconstruct(this DateTime datetime, out int year, out int month) 180 | { 181 | year = datetime.Year; 182 | month = datetime.Month; 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /CsharpSeven/ValueTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Threading.Tasks; 4 | using BenchmarkDotNet.Attributes; 5 | using BenchmarkDotNet.Running; 6 | using Xunit; 7 | 8 | namespace CsharpSeven 9 | { 10 | public class ValueTask 11 | { 12 | [Fact] 13 | public async Task Can_Be_Awaited() 14 | { 15 | ValueTask GetIntAsync() 16 | { 17 | return new ValueTask(1); 18 | } 19 | 20 | /* Setup */ 21 | /* Test */ 22 | var i = await GetIntAsync(); 23 | 24 | /* Assert */ 25 | Assert.Equal(i, 1); 26 | } 27 | 28 | [Fact] 29 | public async Task Can_Be_Async() 30 | { 31 | async ValueTask GetIntAsync() 32 | { 33 | return 1; 34 | } 35 | 36 | /* Setup */ 37 | /* Test */ 38 | var i = await GetIntAsync(); 39 | 40 | /* Assert */ 41 | Assert.Equal(i, 1); 42 | } 43 | 44 | public void Is_Faster_Than_Task() 45 | { 46 | var result = BenchmarkRunner.Run(); 47 | var taskTime = result.Reports[0].ResultStatistics.Mean; 48 | var valueTaskTime = result.Reports[1].ResultStatistics.Mean; 49 | Assert.True(taskTime < valueTaskTime); 50 | } 51 | } 52 | 53 | public class ValueTaskBenchmark 54 | { 55 | [Benchmark] 56 | public async Task TestTask() 57 | { 58 | await Task.Delay(TimeSpan.FromTicks(1)); 59 | return 10; 60 | } 61 | 62 | [Benchmark] 63 | public async ValueTask TestValueTask() 64 | { 65 | await Task.Delay(TimeSpan.FromTicks(1)); 66 | return 10; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # New features in C# 7 2 | 3 | > Test suite of new features in C# 7 4 | 5 | This repo contains a list of new features in C# 7. Examples are heavily influenced from [StackOverflow documentation](http://stackoverflow.com/documentation/c%23/1936/c-sharp-7-0-features#t=201704181446063259477) as well as [this MSDN blog post](https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/). 6 | 7 | ## Topics covered 8 | 9 | * [Binary Literals](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/BinaryLiterals.cs) 10 | * [Local Functions](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/LocalFunctions.cs) 11 | * [`out var` declarations](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/OutVarDeclaration.cs) 12 | * [Pattern Matching](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/PatternMatching.cs) 13 | * [`ref local` and `ref return`](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/RefLocalAndRefReturn.cs) 14 | * [Throwing exceptions](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/ThrowExceptions.cs) 15 | * [Tuples](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/Tuples.cs) 16 | * [ValueTask](https://github.com/pardahlman/csharp-seven/blob/master/CsharpSeven/ValueTask.cs) 17 | 18 | ## Examples 19 | 20 | Introduces object deconstruction, expression bodies and `ValueTuples` 21 | 22 | ```csharp 23 | class Person 24 | { 25 | public string FirstName { get; set; } 26 | public string LastName { get; set; } 27 | public (string First, string Last) FullName => (FirstName, LastName); 28 | 29 | public void Deconstruct(out string first, out string last) 30 | { 31 | first = FirstName; 32 | last = LastName; 33 | } 34 | } 35 | ``` 36 | --------------------------------------------------------------------------------