├── .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 |
--------------------------------------------------------------------------------