{"id":21842504,"url":"https://github.com/erik1066/csharp-features","last_synced_at":"2025-06-21T11:04:18.789Z","repository":{"id":96784608,"uuid":"167870318","full_name":"erik1066/csharp-features","owner":"erik1066","description":"Interesting features of the C# programming language.","archived":false,"fork":false,"pushed_at":"2019-06-09T12:26:43.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-21T16:14:18.717Z","etag":null,"topics":["csharp","examples","features","tutorial"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erik1066.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-27T23:22:09.000Z","updated_at":"2019-06-09T12:26:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"87ae7402-1809-4afb-960c-b84791521598","html_url":"https://github.com/erik1066/csharp-features","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/erik1066/csharp-features","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erik1066%2Fcsharp-features","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erik1066%2Fcsharp-features/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erik1066%2Fcsharp-features/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erik1066%2Fcsharp-features/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erik1066","download_url":"https://codeload.github.com/erik1066/csharp-features/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erik1066%2Fcsharp-features/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261110586,"owners_count":23111062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","examples","features","tutorial"],"created_at":"2024-11-27T22:12:10.148Z","updated_at":"2025-06-21T11:04:13.774Z","avatar_url":"https://github.com/erik1066.png","language":"C#","readme":"# C# Language Features\n\n**Background**: C# (as of version 5.0) is both an [ECMA](https://ecma-international.org/publications/standards/Ecma-334.htm) and ISO/IEC standard. See [ECMA-334](https://ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf). C#'s compiler, [Roslyn](https://github.com/dotnet/roslyn), is written in C# and is open source under the Apache 2.0 license.\n\nC# projects can be compiled and run on macOS, Linux, or Windows when targeting [.NET Core](https://github.com/dotnet/core). The .NET Core runtime and SDK are open source on GitHub and available under the MIT license.\n\nSee [Pop!\\_OS setup guide](https://github.com/erik1066/pop-os-setup) for instructions on installing .NET Core's runtime and SDK on Ubuntu 18.04.\n\nExample \"Hello, World!\" application:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        Console.WriteLine(\"Hello, world!\");\n    }\n}\n```\n\nC# version release dates:\n\n| Version | Date |                                                              ECMA                                                              |\n| ------- | :--: | :----------------------------------------------------------------------------------------------------------------------------: |\n| C# 1.0  | 2002 | [Yes](http://www.ecma-international.org/publications/files/ECMA-ST-WITHDRAWN/ECMA-334,%202nd%20edition,%20December%202002.pdf) |\n| C# 2.0  | 2005 |                        [Yes](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf)                        |\n| C# 3.0  | 2007 |                                                               No                                                               |\n| C# 4.0  | 2010 |                                                               No                                                               |\n| C# 5.0  | 2012 |                       [Yes](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf)                        |\n| C# 6.0  | 2015 |                                                               No                                                               |\n| C# 7.0  | 2017 |                                                               No                                                               |\n| C# 8.0  | 2019 |                                                               No                                                               |\n\n## String interpolation\n\n\u003e Available in C# 6.0. [C# string interpolation](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated)\n\nYou can use string interpolation instead of string concatenation, provided you prefix the string with a `$`:\n\n```cs\nstring name = $\"My name is {firstname} {GetLastname()}\";\n```\n\n## Multiple return values via tuples and deconstruction\n\n\u003e Available in C# 7.0. [C# tuples, deconstruction, and multiple return values](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#tuples)\n\nYou can return multiple values from a function as of C# 7.0, either with names or without names, much like you can in Golang. Multiple return values without names:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        // multiple return types with no names, use 'Item1', 'Item2', etc.\n        (string, string) greetings = Greeting(\"John\");\n\n        Console.WriteLine(greetings.Item1);\n        Console.WriteLine(greetings.Item2);\n    }\n\n    static (string, string) Greeting(string name)\n    {\n        return (\"Hello, \" + name, \"HEY! \" + name);\n    }\n}\n```\n\nMultiple return values with names:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        // multiple return types that use the default property names defined in the Greeting() method (implicit when using var)\n        var greetings1 = Greeting(\"John\");\n\n        Console.WriteLine(greetings1.Regular);\n        Console.WriteLine(greetings1.Excited);\n\n        // multiple return types that use overriden property names\n        (string First, string Second) greetings2 = Greeting(\"Mary\");\n        Console.WriteLine(greetings2.First);\n        Console.WriteLine(greetings2.Second);\n    }\n\n    static (string Regular, string Excited) Greeting(string name)\n    {\n        return (\"Hello, \" + name, \"HEY! \" + name);\n    }\n}\n```\n\n## Implicity-typed variables using `var`\n\n\u003e Available in C# 3.0. [C# var reference](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var)\n\nThe `var` keyword can be used for implicity-typed variables:\n\n```cs\nvar name = \"John\";\nvar age = 25;\nvar birthdate = DateTime.Today;\n```\n\nIt's not recommended to use `var` when the type can't be inferred by reading the code. For example, the following is legal C# code, but bad practice because it's unclear to the reader what `handler` is.\n\n```cs\n// allowed, but a bad practice - it's not clear what 'handler' is\nvar handler = builder.CreateNew(\"http://localhost:9090\");\n```\n\n## Passing functions using delegates\n\n\u003e Available in C# 1.0. [C# delegates](https://docs.microsoft.com/en-us/dotnet/csharp/delegates-overview)\n\n### Basic delegates\n\nLike GoLang and JavaScript, you can pass functions as arguments to other functions. This is done using C# delegates.\n\n```cs\nusing System;\n\npublic delegate string Greeter(string name);\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        Greeter g = CreateGreeting;\n        string greeting = g(\"Bob\");\n        Console.WriteLine(greeting);\n    }\n\n    static string CreateGreeting(string name)\n    {\n        return $\"Hello, {name}!\";\n    }\n}\n```\n\n### Multicast delegates\n\nNote that the special `delegate` type in C# is _multicast_, meaning you can attach multiple functions to the delegate and they will all be called when the delegate is invoked. Attaching is done using the `+=` operator, and detaching is done using the `-=` operator.\n\n```cs\nusing System;\n\npublic delegate void Greeter(string name);\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        Greeter g = DisplayBasicGreeting;\n        g += DisplayHappyGreeting;\n\n        g(\"Bob\"); // displays both \"Hello, Bob\" and \"Hey, Bob!\" to the console\n\n        g -= DisplayBasicGreeting;\n        g -= DisplayHappyGreeting;\n    }\n\n    static void DisplayBasicGreeting(string name)\n    {\n        Console.WriteLine($\"Hello, {name}\");\n    }\n\n    static void DisplayHappyGreeting(string name)\n    {\n        Console.WriteLine($\"Hey, {name}!\");\n    }\n}\n```\n\n### Generic delegates\n\nGeneric programming works with delegates:\n\n```cs\nusing System;\n\npublic delegate T Greeter\u003cT\u003e(T arg1, T arg2);\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        Greeter\u003cstring\u003e g = CreateGreeting;\n        string greeting = g(\"Susan\", \"Dr.\");\n        Console.WriteLine(greeting);\n    }\n\n    static string CreateGreeting(string name, string title)\n    {\n        return $\"Hello, {title} {name}!\";\n    }\n}\n```\n\n## Digit separators\n\n\u003e Available in C# 7.0. [C# numeric literal improvements](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#numeric-literal-syntax-improvements)\n\nC# allows the use of underscores to separate digits in numeric literals. For example:\n\n```csharp\nint amount = 1_000_000;\n```\n\n## Declaring `out` variables on-the-fly and `out` discards\n\n\u003e Available in C# 7.0.\n\n`out` variables can now be declared on-the-fly:\n\n```cs\n// The C# 7 way of handling out variables\nbool success = int.TryParse(\"ABCD\", out int result);\nConsole.WriteLine(result);\n```\n\nIn older versions of C#, we'd need to instead declare `result` earlier, like this:\n\n```cs\n// The old way of handling out variables\nint result;\nbool success = int.TryParse(\"ABCD\", out result);\nConsole.WriteLine(result);\n```\n\nIn addition to delcaring `out` variables on-the-fly, you can now _discard_ `out` variables you don't want using the `_` symbol:\n\n```cs\nTransform(out _, out _, out int data, out _);\n```\n\n## Patterns\n\n\u003e Available in C# 7.0. [C# pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching)\n\nYou can also declare variables on-the-fly with the `is` operator:\n\n```cs\npublic void Transform(object data)\n{\n    if (data is DateTime dt)\n    {\n        Console.WriteLine(\"Day of month: \" + dt.Day);\n    }\n    else if (data is string s)\n    {\n        Console.WriteLine($\"String '{s}' has a length of {s.Length}\");\n    }\n    else\n    {\n        Console.WriteLine(\"Unsupported data detected\");\n    }\n}\n```\n\nDeclaring variables with an `is` operator makes those variables \"pattern variables.\" We can also do this with `switch` statements as shown below.\n\n```cs\npublic void Transform(object data)\n{\n    switch (data)\n    {\n        case int i:\n            Console.WriteLine(\"Int detected: \" + i);\n            break;\n        case DateTime dt:\n            Console.WriteLine(\"DateTime detected: \" + dt.ToShortDateString());\n            break;\n        case string s when s.Length \u003e= 5:\n            Console.WriteLine(\"String detected: \" + s);\n            break;\n        case string s when s.Length \u003c 5:\n            Console.WriteLine(\"Short string detected: \" + s);\n            break;\n        case bool b when b == false:\n            Console.WriteLine(\"FALSE\");\n            break;\n    }\n}\n```\n\n## Dynamic binding\n\n\u003e Available in C# 4.0. [C# dynamic binding](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic)\n\nYou can defer the binding of property names to objects from _compile time_ to _runtime_ using the `dynamic` keyword.\n\n```cs\ndynamic person = new Person();\nperson.Speak();\n```\n\nIn this case, we're telling the compiler to avoid checking to see if `Speak()` actually exists on `Person`. Dynamic binding can be useful when interoperating with dynamic languages.\n\n## Named arguments\n\n\u003e Available in C# 4.0. [C# named and optional arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments)\n\nYou can provide arguments to a method in one of two ways. The first way is by providing the arguments in a comma-separated list in the order they are defined in the method definition, as shown below:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        var greeting = Greeting(\"Sonya\", \"Hello\");\n\n        Console.WriteLine(greeting); // \"Hello, Sonya\"\n    }\n\n    static string Greeting(string name, string greeting)\n    {\n        return greeting + \", \" + name;\n    }\n}\n```\n\nWe can be more explicit, however, and use _named arguments_ as of C# 4.0:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        var greeting = Greeting(name: \"Sonya\", greeting: \"Hello\");\n\n        Console.WriteLine(greeting); // \"Hello, Sonya\"\n    }\n\n    static string Greeting(string name, string greeting)\n    {\n        return greeting + \", \" + name;\n    }\n}\n```\n\nWith named arguments, the order of the arguments no longer matters. We can provide the arguments in any order we want.\n\n## Default values for method parameters\n\n\u003e Available in C# 4.0. [C# named and optional arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments)\n\nMethod parameters can have default values:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        var greeting = Greeting(name: \"Sonya\", greeting: \"Hello\");\n\n        Console.WriteLine(greeting); // \"Hello, Sonya!\"\n    }\n\n    static string Greeting(string name, string greeting, string terminator = \"!\")\n    {\n        return greeting + \", \" + name + terminator;\n    }\n}\n```\n\n## Anonymous types\n\n\u003e Available in C# 3.0. [C# anonymous types reference](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types)\n\nAnonymous types allow the programmer to create read-only objects on-the-fly.\n\n```cs\nvar person = new { FirstName = \"Andy\", LastName = \"Dwyer\", Age = 30 };\n```\n\nBehind-the-scenes, the C# compiler creates a class with readonly properties for the `FirstName`, `LastName`, and `Age` fields.\n\nNote that it's illegal to return an anonymous object from a method because you cannot return `var`. If you must do this, you can use the `dynamic` keyword or use an `object` and rely on other aspects of C# and .NET to obtain the values (these features are not discussed here, however).\n\n## Tuples\n\n\u003e Available in C# 7.0. [C# tuple reference](https://docs.microsoft.com/en-us/dotnet/csharp/tuples)\n\nTuples allow storing a set of values, much like anonymous types. Their primary reason for existence is to allow returning multiple values from a method, something an anonymous type cannot do.\n\n```cs\nvar person = (\"Andy\", \"Dwyer\", 30);\n\nConsole.WriteLine(person.Item1); // Andy\nConsole.WriteLine(person.Item2); // Dwyer\nConsole.WriteLine(person.Item3); // 30\n```\n\nYou can specify tuple types explicitly. Doing so is how we can return a tuples from a method:\n\n```cs\n(string, string, int) person = (\"Andy\", \"Dwyer\", 30);\n```\n\nThat means this is legal:\n\n```cs\n(string, string, int) person = GetPerson();\n```\n\nWe can name our tuple parameters:\n\n```cs\nvar person = (Firstname: \"Andy\", Lastname: \"Dwyer\", Age: 30);\n\nConsole.WriteLine(person.Firstname); // Andy\nConsole.WriteLine(person.Lastname); // Dwyer\nConsole.WriteLine(person.Age); // 30\n```\n\nAnd we can specify them from the return values:\n\n```cs\n(string Firstname, string Lastname, int Age) person = GetPerson();\n\nConsole.WriteLine(person.Firstname);\nConsole.WriteLine(person.Lastname);\nConsole.WriteLine(person.Age);\n```\n\nC# 7 also added support for _deconstruction_ using tuples. Thus, this is legal:\n\n```cs\nvar person = (\"Andy\", \"Dwyer\", 30);\n\n(string first, string last, int age) = person;\n\nConsole.WriteLine(first); // Andy\nConsole.WriteLine(last); // Dwyer\nConsole.WriteLine(age); // 30\n```\n\nThe `Equals` method is overriden such that two tuples are equal if their values are equal. For example:\n\n```cs\nvar person1 = (\"April\", \"Ludgate\", 25);\nvar person2 = (\"April\", \"Ludgate\", 25);\n\nConsole.WriteLine(person1.Equals(person2)); // true\n```\n\n## Foreach loops\n\n\u003e Available in C# 1.0.\n\nIn addition to the `for` loop, C# has a `foreach` loop:\n\n```cs\nforeach (string name in names)\n{\n    Console.WriteLine(name);\n}\n```\n\nYou can use Lambdas in the loop expression, too:\n\n```cs\nforeach (var name in names.Where(n =\u003e n.StartsWith(\"J\")))\n{\n    Console.WriteLine(name);\n}\n```\n\n## Collection initializers\n\n\u003e Available in C# 3.0. Note that the special dictionary initializer is available in C# 6.0.\n\nPreviously, collections could only be populated after they were initialized:\n\n```cs\nvar names = new List\u003cstring\u003e();\nnames.Add(\"John\");\nnames.Add(\"Susan\");\nnames.Add(\"Maria\");\nnames.Add(\"Sonya\");\n```\n\nHowever, in C# 3.0, we can now populate collections at the time they're initialized in a single line of code:\n\n```cs\nvar names = new List\u003cstring\u003e()\n{\n    \"John\", \"Susan\", \"Maria\", \"Sonya\"\n};\n```\n\nDictionaries can be initialized this way starting in C# 6.0:\n\n```cs\nvar codeLookup = new Dictionary\u003cint, string\u003e()\n{\n    { 400, \"Bad Request\" },\n    { 404, \"Not Found\" }\n};\n```\n\nAn alternative syntax that's equivalent to the one above:\n\n```cs\nvar codeLookup = new Dictionary\u003cint, string\u003e()\n{\n    [400] = \"Bad Request\",\n    [404] = \"Not Found\"\n};\n```\n\n## Properties\n\n\u003e Available in C# 1.0. [C# properties](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties)\n\nC# provides syntatic sugar for getter and setter methods around private data fields via the `get` and `set` keywords. In the example below, `Hours` is a C# property with both `get` and `set` methods:\n\n```cs\nusing System;\n\nclass TimePeriod\n{\n   private double _seconds;\n\n   public double Hours\n   {\n       get { return _seconds / 3600; }\n       set {\n          if (value \u003c 0 || value \u003e 24)\n             throw new ArgumentOutOfRangeException(\n                   $\"{nameof(value)} must be between 0 and 24.\");\n\n          _seconds = value * 3600;\n       }\n   }\n}\n```\n\n_Without_ `get` and `set`, the above code snippet would look like the following:\n\n```cs\nusing System;\n\nclass TimePeriod\n{\n   private double _seconds;\n\n   public GetHours()\n   {\n       return _seconds / 3600;\n   }\n\n   public SetHours(double hours)\n   {\n        if (hours \u003c 0 || hours \u003e 24)\n             throw new ArgumentOutOfRangeException(\n                   $\"{nameof(value)} must be between 0 and 24.\");\n\n          _seconds = value * 3600;\n   }\n}\n```\n\nUsing properties is straightforward:\n\n```cs\nTimePeriod period = new TimePeriod();\nperiod.Hours = 24;\ndouble hours = period.Hours;\n```\n\nWhat if you don't need to execute logic in the `get` and `set` methods as shown above? C# allows auto-generation of backing fields for properties when they're just pass-throughs:\n\n```cs\nusing System;\n\nclass Book\n{\n    public string Title { get; set; }\n    public int Pages { get; set; }\n}\n```\n\nC# allows default values to be set using this syntax, too:\n\n```cs\nusing System;\n\nclass Book\n{\n    public string Title { get; set; } = string.Empty;\n    public int Pages { get; set; } = 0;\n}\n```\n\nAccess modifiers can be used with the `get` and `set` keywords. In the example below, `Title` can be retrieved by any caller but is only set-able by class methods. `Pages` is effectively read-only, although C# allows the constructor to set a value.\n\n```cs\nusing System;\n\nclass Book\n{\n    public string Title { get; private set; }\n    public int Pages { get; }\n\n    public Book(string title, int pages)\n    {\n        Title = title;\n        Pages = pages; // allowed, but only in the constructor\n    }\n}\n```\n\n## Local functions\n\n\u003e Available in C# 7.0. [C# local functions reference](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/local-functions)\n\n```cs\nusing System;\nusing System.Collections.Generic;\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        var names = new List\u003cstring\u003e()\n        {\n            \"John\",\n            \"Maria\",\n            \"Ava\",\n            \"Fransico\",\n        };\n\n        foreach (var name in names)\n        {\n            string greeting = GenerateGreeting(name); // calls the local function\n            Console.WriteLine(greeting);\n        }\n\n        // local function declaration\n        string GenerateGreeting(string name)\n        {\n            Random rnd = new Random();\n            int month = rnd.Next(1, 3);\n\n            string greeting = \"\";\n\n            switch (month)\n            {\n                case 1:\n                    greeting = \"Greetings\";\n                    break;\n                case 2:\n                    greeting = \"Salutations\";\n                    break;\n                case 3:\n                    greeting = \"Hello\";\n                    break;\n            }\n\n            greeting = greeting + \", \" + name;\n            return greeting;\n        }\n    }\n}\n\n```\n\n## Obsolete methods\n\nYou can decorate methods with the `[Obsolete]` attribute to mark them as deprecated. Using obsolete methods generates a compiler warning.\n\n```cs\nusing System.Attribute;\n\npublic class Builder\n{\n    [Obsolete]\n    public string Build()\n    {\n        ...\n    }\n}\n```\n\n## Null coalesing operator\n\n\u003e Available in C# 2.0. [C# ?? operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator)\n\nThe old way of checking for a null and then assigning a value \"if not null\" required several lines of C# code. We can now do the same thing with the null coalesing operator. In the code below, if `newTitle` is not null, then assign `newTitle` to `title`. Otherwise, assign `title` the value \"War and Peace\".\n\n```cs\nstring title = newTitle ?? \"War and Peace\";\n```\n\nYou can also throw exceptions after the `??` operator:\n\n```cs\nstring title = newTitle ?? throw new ArgumentNullException(nameof(newTitle));\n```\n\n## Safe navigation operator\n\n\u003e Available in C# 6.0. [C# ?. and .[] operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators)\n\nThe `?` operator assigns `null` if the reference it's checking is null. This eliminates the need for boilerplate null-checking logic. For example:\n\n```cs\nstring authorName = books?[0]?.author?.name;\n```\n\nIn older versions of C#, to implement the same logic, we'd have had to check three entities for `null`: The `books` array, the first item in the `books` array, and the `author` property of the book.\n\n## Ranges\n\n\u003e Available in C# 8.0\n\nStarting in C# 8.0, we can use the `[start...end]` syntax on collections and arrays in `foreach` loops:\n\n```cs\nusing System;\n\nclass Program\n{\n    static void Main(string[] args)\n    {\n        var names = new string[]\n        {\n            \"Mary\",\n            \"Maria\",\n            \"Mario\",\n            \"Denise\",\n            \"Henry\"\n        };\n\n        foreach (var name in names[1..4])\n        {\n            Console.WriteLine(name);\n        }\n    }\n}\n```\n\nRanges can be shortcut by leaving either the `start` or `end` empty. For instance:\n\n```cs\nforeach (var name in names[1..])\n```\n\nOutput:\n\n```\nMaria\nMario\nDenise\nHenry\n```\n\nWhen we leave off the `start` value instead:\n\n```cs\nforeach (var name in names[..3])\n```\n\nOutput:\n\n```\nMary\nMaria\nMario\n```\n\nWe can also use the `^` operator as a prefix to the `end` value to tell C# to treat that value as _n values from the end_. The `^1` in the example below indicates that we should stop \"one before the last item\":\n\n```cs\nforeach (var name in names[1..^1])\n```\n\nOutput:\n\n```\nMaria\nMario\nDenise\n```\n\nWe can also create a `Range` object and use it instead of literal integer values:\n\n```cs\nRange range = 1..4;\nforeach (var name in names[range])\n```\n\n## Verbatim Strings\n\nWe can create strings that don't need to be escaped by using the `@` operator:\n\n```cs\nstring names = @\"\n                 John\n                 Harry\n                 Mary\";\n```\n\nOutput:\n\n```\n\n                 John\n                 Harry\n                 Mary\n```\n\n## Nested using statements\n\nIf you've been using C# and objects that implement `IDisposable` for long enough, you're familar with the following `using` syntax for disposing of managed resources:\n\n```cs\nusing (var reader = new System.IO.StreamReader(csv.OpenReadStream()))\n{\n    ...\n}\n```\n\nBut we often need to nest `using` statements, like such:\n\n```cs\nusing (var reader = new System.IO.StreamReader(csv.OpenReadStream()))\n{\n    using (var csvReader = new ChoCSVReader(reader).WithFirstLineHeader())\n    {\n        foreach (var row in csvReader)\n        {\n            rows.Add(row.DumpAsJson());\n        }\n    }\n}\n```\n\nThankfully there's a more concise way to represent nested `using` statements:\n\n```cs\nusing (var reader = new System.IO.StreamReader(csv.OpenReadStream()))\nusing (var csvReader = new ChoCSVReader(reader).WithFirstLineHeader())\n{\n    foreach (var row in csvReader)\n    {\n        rows.Add(row.DumpAsJson());\n    }\n}\n```\n\n## Default interface implemention\n\n\u003e Available in C# 8.0\n\nWe can now include a default implementation for interfaces, much like Java:\n\n```cs\npublic interface IEntity\n{\n    int Id { get; set; }\n    void GenerateId()\n    {\n        Id = System.Guid.NewGuid();\n    }\n}\n```\n\nDoing so enables developers to expand an interface's surface area without breaking compatibility with existing implementations of that interface.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferik1066%2Fcsharp-features","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferik1066%2Fcsharp-features","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferik1066%2Fcsharp-features/lists"}