├── csharp11 ├── 8. File scoped types │ ├── Builder.cs │ ├── GeneratedBuilder.cs │ └── 8. File scoped types.csproj ├── 3. Newlines in string interpolations │ ├── Program.cs │ └── 3. Newlines in string interpolations.csproj ├── 7. Utf8 String Literals │ ├── Program.cs │ └── 7. Utf8 String Literals.csproj ├── 4. List patterns │ ├── 4. List patterns.csproj │ └── Program.cs ├── 2. Generic Attributes │ ├── 2. Generic Attributes.csproj │ └── Program.cs ├── 5. RawStringLiterals │ ├── 5. Raw String Literals.csproj │ └── Program.cs ├── 1. Auto Default Structs │ ├── 1. Auto Default Structs.csproj │ └── Program.cs ├── 6. Generic math support │ ├── 6. Generic math support.csproj │ └── Program.cs ├── 9. Required Properties │ ├── 9. Required Properties.csproj │ └── Program.cs ├── Csharp11.sln └── ReadMe.md ├── csharp9 ├── 1. TopLevelStatement │ ├── Program.cs │ └── 1. TopLevelStatement.csproj ├── 2. Records │ ├── 2. Records.csproj │ └── Program.cs ├── 3. TargetTypedObject │ ├── 3. TargetTypedObject.csproj │ └── Program.cs ├── 4. InitOnlySetters │ ├── 4. InitOnlySetters.csproj │ └── Program.cs ├── 7. CovariantReturns │ ├── 7. CovariantReturns.csproj │ └── Program.cs ├── 6. ExtendedPartialMethods │ ├── 6. ExtendedPartialMethods.csproj │ └── Program.cs ├── 5. RelationalAndLogicalPatterns │ ├── 5. RelationalAndLogicalPatterns.csproj │ └── Program.cs ├── CSharp9Features.sln └── ReadMe.md ├── csharp10 ├── 4. Records │ ├── Point.cs │ ├── 4. Records.csproj │ └── Circle.cs ├── 6. Global Using directive │ ├── GlobalUsings.cs │ ├── Author.cs │ ├── Store.cs │ ├── 6. Global Using directive.csproj │ └── Book.cs ├── 7. Structure Types │ ├── Program.cs │ ├── 7. Structure Types.csproj │ └── Point.cs ├── 1. File-Scoped Namespace │ ├── Book.cs │ ├── Author.cs │ └── 1. File-Scoped Namespace.csproj ├── Csharp10 │ ├── Program.cs │ └── 0. Console Template.csproj ├── 2. Extended Property Patterns │ ├── Author.cs │ ├── 2. Extended Property Patterns.csproj │ └── Book.cs ├── 3. Constant Interpolated Strings │ ├── Author.cs │ ├── 3. Constant Interpolated Strings.csproj │ └── Book.cs ├── 5. Deconstruction │ ├── 5. Deconstruction.csproj │ ├── Author.cs │ └── Program.cs ├── Csharp10.sln └── ReadMe.md ├── csharp12 ├── 8. Interceptors │ ├── Program.cs │ ├── Sender.cs │ ├── InterceptsLocationAttribute.cs │ ├── Hacker.cs │ └── 8. Interceptors.csproj ├── 5. Default lambda parameters │ ├── Program.cs │ └── 5. Default lambda parameters.csproj ├── 1. Alias any type │ ├── Program.cs │ └── 1. Alias any type.csproj ├── 7. Experimental attribute │ ├── Program.cs │ └── 7. Experimental attribute.csproj ├── 4. Inline arrays │ ├── Program.cs │ └── 4. Inline arrays.csproj ├── 6. Ref readonly │ ├── 6. Ref readonly.csproj │ └── Program.cs ├── 2. Primary constructors │ ├── 2. Primary constructors.csproj │ └── Program.cs ├── 3. Collection expressions │ ├── 3. Collection expressions.csproj │ └── Program.cs ├── csharp12-features.sln └── ReadMe.md ├── csharp13 ├── 4. New Escape Sequence │ ├── Program.cs │ └── 4. New Escape Sequence.csproj ├── 1. Params Collections │ ├── Program.cs │ └── 1. Params Collections.csproj ├── 3. New Lock Object │ ├── 3. New Lock Object.csproj │ └── Program.cs ├── 8. Allows Ref Struct │ ├── 8. Allows Ref Struct.csproj │ └── Program.cs ├── 10. More Partial Members │ ├── 10. More Partial Members.csproj │ └── Program.cs ├── 11. Field Keyword │ ├── 11. Field Keyword.csproj │ └── Program.cs ├── 6. Implicit Index Access │ ├── 6. Implicit Index Access.csproj │ └── Program.cs ├── 9. Ref Struct Interfaces │ ├── 9. Ref Struct Interfaces.csproj │ └── Program.cs ├── 5. Method Group Natural Type │ ├── 5. Method Group Natural Type.csproj │ └── Program.cs ├── 2. Overload Resolution Priority │ ├── 2. Overload Resolution Priority.csproj │ └── Program.cs ├── 7. Ref and Unsafe in Async and Iterators │ ├── 7. Ref and Unsafe in Async and Iterators.csproj │ └── Program.cs ├── csharp13-features.sln └── ReadMe.md ├── README.md └── .gitignore /csharp11/8. File scoped types/Builder.cs: -------------------------------------------------------------------------------- 1 | class Builder 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /csharp11/8. File scoped types/GeneratedBuilder.cs: -------------------------------------------------------------------------------- 1 | file class Builder 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /csharp9/1. TopLevelStatement/Program.cs: -------------------------------------------------------------------------------- 1 | System.Console.WriteLine("Hello World!"); 2 | -------------------------------------------------------------------------------- /csharp10/4. Records/Point.cs: -------------------------------------------------------------------------------- 1 | namespace _4._Records; 2 | 3 | public readonly record struct Point(int X, int Y); 4 | -------------------------------------------------------------------------------- /csharp12/8. Interceptors/Program.cs: -------------------------------------------------------------------------------- 1 | using _8._Interceptors; 2 | 3 | var sender = new Sender(); 4 | sender.SendMessage(); -------------------------------------------------------------------------------- /csharp10/6. Global Using directive/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using System.Collections.Generic; 2 | global using System.Linq; 3 | 4 | -------------------------------------------------------------------------------- /csharp13/4. New Escape Sequence/Program.cs: -------------------------------------------------------------------------------- 1 | const string previousEscape = "\u001b"; 2 | const string previousEscapeNotRecommended = "\x1b"; 3 | const string newEscape = "\e"; -------------------------------------------------------------------------------- /csharp12/5. Default lambda parameters/Program.cs: -------------------------------------------------------------------------------- 1 | var setVolume = (int value = 0) => $"The volume is set to {value}"; 2 | 3 | Console.WriteLine(setVolume()); 4 | Console.WriteLine(setVolume(4)); 5 | -------------------------------------------------------------------------------- /csharp12/8. Interceptors/Sender.cs: -------------------------------------------------------------------------------- 1 | namespace _8._Interceptors; 2 | 3 | public class Sender 4 | { 5 | public void SendMessage() 6 | { 7 | Console.WriteLine("Hello everyone!"); 8 | } 9 | } -------------------------------------------------------------------------------- /csharp10/7. Structure Types/Program.cs: -------------------------------------------------------------------------------- 1 | var point = new Point(1,2); 2 | Console.WriteLine(point); 3 | 4 | var point2 = new Point(); 5 | Console.WriteLine(point2); 6 | 7 | var point3 = default(Point); 8 | Console.WriteLine(point3); 9 | -------------------------------------------------------------------------------- /csharp9/2. Records/2. Records.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp11/3. Newlines in string interpolations/Program.cs: -------------------------------------------------------------------------------- 1 | var number1 = 1; 2 | var number2 = 2; 3 | var test = true; 4 | 5 | _ = $"interpolated string with value {(test 6 | ? number1 7 | : number2 8 | )}, and some more text ..."; -------------------------------------------------------------------------------- /csharp12/1. Alias any type/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dec = decimal; // вместо System.Decimal 3 | using SomethingAbstract = (string, decimal); 4 | using Grade = (string Course, decimal Value); 5 | using unsafe p = decimal*; 6 | Console.ReadLine(); -------------------------------------------------------------------------------- /csharp9/3. TargetTypedObject/3. TargetTypedObject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp9/4. InitOnlySetters/4. InitOnlySetters.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp9/7. CovariantReturns/7. CovariantReturns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp10/1. File-Scoped Namespace/Book.cs: -------------------------------------------------------------------------------- 1 | namespace _1._File_Scoped_Namespace; 2 | public class Book 3 | { 4 | public string Title { get; set; } 5 | public Author Author { get; set; } 6 | public Book(string title, Author author) => 7 | (Title, Author) = (title, author); 8 | } -------------------------------------------------------------------------------- /csharp10/Csharp10/Program.cs: -------------------------------------------------------------------------------- 1 | Console.WriteLine("Hello World!"); 2 | 3 | //namespace HelloWorld 4 | //{ 5 | // class Program 6 | // { 7 | // static void Main(string[] args) 8 | // { 9 | // Console.WriteLine("Hello World!"); 10 | // } 11 | // } 12 | //} -------------------------------------------------------------------------------- /csharp10/6. Global Using directive/Author.cs: -------------------------------------------------------------------------------- 1 | namespace _6._Global_Using_directive; 2 | public class Author 3 | { 4 | public string Name { get; set; } 5 | public string LastName { get; set; } 6 | public Author(string name, string lastname) => 7 | (Name, LastName) = (name, lastname); 8 | } 9 | -------------------------------------------------------------------------------- /csharp10/2. Extended Property Patterns/Author.cs: -------------------------------------------------------------------------------- 1 | namespace _2._Extended_Property_Patterns; 2 | public class Author 3 | { 4 | public string Name { get; set; } 5 | public string LastName { get; set; } 6 | public Author(string name, string lastname) => 7 | (Name, LastName) = (name, lastname); 8 | } 9 | -------------------------------------------------------------------------------- /csharp10/3. Constant Interpolated Strings/Author.cs: -------------------------------------------------------------------------------- 1 | namespace _3._Constant_Interpolated_Strings; 2 | public class Author 3 | { 4 | public string Name { get; set; } 5 | public string LastName { get; set; } 6 | public Author(string name, string lastname) => 7 | (Name, LastName) = (name, lastname); 8 | } -------------------------------------------------------------------------------- /csharp12/7. Experimental attribute/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | #pragma warning disable Danger_Identifier 4 | var feature = new DangerFeature(); 5 | #pragma warning restore Danger_Identifier 6 | 7 | [Experimental("Danger_Identifier")] 8 | internal class DangerFeature 9 | { 10 | } -------------------------------------------------------------------------------- /csharp9/1. TopLevelStatement/1. TopLevelStatement.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | TopLevelStatement 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /csharp10/Csharp10/0. Console Template.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp10/4. Records/4. Records.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | _4._Records 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp9/6. ExtendedPartialMethods/6. ExtendedPartialMethods.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | ExtendedPartialMethods 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /csharp12/4. Inline arrays/Program.cs: -------------------------------------------------------------------------------- 1 | var buffer = new Buffer(); 2 | for (var i = 0; i < 10; i++) 3 | { 4 | buffer[i] = i; 5 | } 6 | 7 | foreach (var i in buffer) 8 | { 9 | Console.WriteLine(i); 10 | } 11 | 12 | [System.Runtime.CompilerServices.InlineArray(10)] 13 | internal struct Buffer 14 | { 15 | private int _; 16 | } -------------------------------------------------------------------------------- /csharp10/6. Global Using directive/Store.cs: -------------------------------------------------------------------------------- 1 | namespace _6._Global_Using_directive; 2 | public class Store 3 | { 4 | private readonly IEnumerable Books; 5 | public Store(IEnumerable books) => Books = books; 6 | public IEnumerable GetBooks(Author author) => 7 | Books.Where(b => b.Author.LastName == author.LastName); 8 | } -------------------------------------------------------------------------------- /csharp9/5. RelationalAndLogicalPatterns/5. RelationalAndLogicalPatterns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp5.0 6 | RelationalAndLogicalPatterns 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /csharp12/8. Interceptors/InterceptsLocationAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices 2 | { 3 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 4 | sealed class InterceptsLocationAttribute( 5 | string filePath, 6 | int line, 7 | int column) 8 | : Attribute 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /csharp10/1. File-Scoped Namespace/Author.cs: -------------------------------------------------------------------------------- 1 | namespace _1._File_Scoped_Namespace 2 | { 3 | public class Author 4 | { 5 | public string Name { get; set; } 6 | public string LastName { get; set; } 7 | public Author(string name, string lastname) => 8 | (Name, LastName) = (name, lastname); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /csharp10/4. Records/Circle.cs: -------------------------------------------------------------------------------- 1 | namespace _4._Records; 2 | record Circle 3 | { 4 | public sealed override string ToString() 5 | { 6 | return typeof(Circle).Name; 7 | } 8 | } 9 | 10 | record BigCircle : Circle 11 | { 12 | //public override string ToString() 13 | //{ 14 | // return typeof(BigCircle).Name; 15 | //} 16 | } 17 | -------------------------------------------------------------------------------- /csharp10/1. File-Scoped Namespace/1. File-Scoped Namespace.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | _1._File_Scoped_Namespace 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp10/6. Global Using directive/6. Global Using directive.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | _6._Global_Using_directive 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp11/7. Utf8 String Literals/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | ReadOnlySpan value1 = new byte[12] 4 | { 5 | 72, 101, 108, 108, 111, 32, 6 | 119, 111, 114, 108, 100, 33 7 | }; 8 | 9 | ReadOnlySpan value2 = "Hello world!"u8; 10 | 11 | Console.WriteLine(Encoding.UTF8.GetString(value1)); 12 | Console.WriteLine(Encoding.UTF8.GetString(value2)); 13 | -------------------------------------------------------------------------------- /csharp10/2. Extended Property Patterns/2. Extended Property Patterns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | _2._Extended_Property_Patterns 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp11/4. List patterns/4. List patterns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _4._List_patterns 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp10/5. Deconstruction/5. Deconstruction.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | _5._Deconstruction 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp10/7. Structure Types/7. Structure Types.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | _7._Structure_Types 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp10/3. Constant Interpolated Strings/3. Constant Interpolated Strings.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | _3._Constant_Interpolated_Strings 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp11/2. Generic Attributes/2. Generic Attributes.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _2._Generic_Attributes 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/5. RawStringLiterals/5. Raw String Literals.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _5._RawStringLiterals 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/8. File scoped types/8. File scoped types.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _8._File_scoped_types 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/1. Auto Default Structs/1. Auto Default Structs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _1._Auto_Default_Structs 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/6. Generic math support/6. Generic math support.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _6._Generic_math_support 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/7. Utf8 String Literals/7. Utf8 String Literals.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _7._Utf8_String_Literals 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/9. Required Properties/9. Required Properties.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | _9._Required_Properties 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/6. Ref readonly/6. Ref readonly.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _6._Ref_readonly 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp10/7. Structure Types/Point.cs: -------------------------------------------------------------------------------- 1 | public struct Point 2 | { 3 | public Point() 4 | { 5 | X = double.NaN; 6 | Y = double.NaN; 7 | } 8 | public Point(double x, double y) => 9 | (X, Y) = (x, y); 10 | 11 | public double X { get; set; } 12 | public double Y { get; set; } 13 | 14 | public override string ToString() => 15 | $"X: {X}, Y: {Y}"; 16 | } 17 | -------------------------------------------------------------------------------- /csharp12/4. Inline arrays/4. Inline arrays.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _4._Inline_arrays 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/1. Params Collections/Program.cs: -------------------------------------------------------------------------------- 1 | ReadOnlySpan text = new(["Hello", "ReadOnlySpan", "World"]); 2 | Printer.PrintElements(text); 3 | 4 | internal static class Printer 5 | { 6 | internal static void PrintElements(params ReadOnlySpan elements) 7 | { 8 | foreach (var element in elements) 9 | { 10 | Console.WriteLine(element); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /csharp10/6. Global Using directive/Book.cs: -------------------------------------------------------------------------------- 1 | namespace _6._Global_Using_directive; 2 | public class Book 3 | { 4 | public string Title { get; set; } 5 | public Author Author { get; set; } 6 | public Book(string title, Author author) => 7 | (Title, Author) = (title, author); 8 | 9 | public static bool doesHaveDiscount(Book book) 10 | { 11 | return false; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /csharp13/3. New Lock Object/3. New Lock Object.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _3._New_Lock_Object 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/8. Allows Ref Struct/8. Allows Ref Struct.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _8._Allows_Ref_Struct 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/1. Params Collections/1. Params Collections.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _1._Params_Collections 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/2. Primary constructors/2. Primary constructors.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _2._Primary_constructors 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/4. New Escape Sequence/4. New Escape Sequence.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _4._New_Escape_Sequence 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/3. Collection expressions/3. Collection expressions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _3._Collection_expressions 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/7. Experimental attribute/7. Experimental attribute.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _7._Experimental_attribute 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/10. More Partial Members/10. More Partial Members.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _10._More_Partial_Members 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/11. Field Keyword/11. Field Keyword.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _11._Field_Keyword 7 | enable 8 | enable 9 | preview 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp13/11. Field Keyword/Program.cs: -------------------------------------------------------------------------------- 1 | Console.WriteLine("Just a hack to make a program compilable"); 2 | 3 | // preview must be set in csproj 4 | class TimePeriod 5 | { 6 | public double Hours { 7 | get; 8 | set => field = (value >= 0) 9 | ? value 10 | : throw new ArgumentOutOfRangeException(nameof(value), "The value must not be negative"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /csharp13/6. Implicit Index Access/6. Implicit Index Access.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _6._Implicit_Index_Access 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/9. Ref Struct Interfaces/9. Ref Struct Interfaces.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _9._Ref_Struct_Interfaces 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/3. Newlines in string interpolations/3. Newlines in string interpolations.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | Newlines_in_string_interpolations 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/1. Alias any type/1. Alias any type.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _1._Alias_any_type 7 | enable 8 | enable 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp12/5. Default lambda parameters/5. Default lambda parameters.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _5._Default_lambda_parameters 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp13/5. Method Group Natural Type/5. Method Group Natural Type.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _5._Method_Group_Natural_Type 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp11/1. Auto Default Structs/Program.cs: -------------------------------------------------------------------------------- 1 | var data = new Data(); 2 | Console.WriteLine(data); 3 | readonly struct Data 4 | { 5 | public decimal Number { get; init; } 6 | public string Text { get; init; } 7 | public DateTime Date { get; init; } 8 | 9 | public Data() 10 | { 11 | Text = string.Empty; 12 | } 13 | 14 | public override string ToString() => $"Number: {Number}, Text: {Text}, Date: {Date}."; 15 | } 16 | -------------------------------------------------------------------------------- /csharp13/8. Allows Ref Struct/Program.cs: -------------------------------------------------------------------------------- 1 | var notifier = new Notifier>(); 2 | var notifier2 = new Notifier(); 3 | 4 | public class Notifier where T : allows ref struct 5 | { 6 | // Use T as a ref struct: 7 | public void Notify(scoped T p) 8 | { 9 | // The parameter p must follow ref safety rules 10 | } 11 | } 12 | 13 | public ref struct Data 14 | { 15 | public int Value { get; set; } 16 | } -------------------------------------------------------------------------------- /csharp13/2. Overload Resolution Priority/2. Overload Resolution Priority.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _2._Overload_Resolution_Priority 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /csharp12/8. Interceptors/Hacker.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using _8._Interceptors; 3 | 4 | namespace HackerSpace; 5 | 6 | public static class Hacker 7 | { 8 | [InterceptsLocation( 9 | @"C:\Users\Andrei\source\repos\platinum\csharp12-features\8. Interceptors\Program.cs", 10 | 4, 11 | 8)] 12 | public static void InterceptMessage(this Sender sender) 13 | { 14 | Console.WriteLine("You're hacked"); 15 | } 16 | } -------------------------------------------------------------------------------- /csharp10/5. Deconstruction/Author.cs: -------------------------------------------------------------------------------- 1 | internal class Author 2 | { 3 | public string Name { get; set; } 4 | public string LastName { get; set; } 5 | public Author(string name, string lastname) => 6 | (Name, LastName) = (name, lastname); 7 | 8 | public void Deconstruct(out string name, out string lastname) => 9 | (name, lastname) = (Name, LastName); 10 | 11 | public override string ToString() => 12 | $"{Name} {LastName}"; 13 | } 14 | -------------------------------------------------------------------------------- /csharp12/8. Interceptors/8. Interceptors.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | _8._Interceptors 7 | enable 8 | enable 9 | $(InterceptorsPreviewNamespaces);HackerSpace 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp13/7. Ref and Unsafe in Async and Iterators/7. Ref and Unsafe in Async and Iterators.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | _7._Ref_and_Unsafe_in_Async_and_Iterators 7 | enable 8 | enable 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp10/2. Extended Property Patterns/Book.cs: -------------------------------------------------------------------------------- 1 | namespace _2._Extended_Property_Patterns; 2 | public class Book 3 | { 4 | public string Title { get; set; } 5 | public Author Author { get; set; } 6 | public Book(string title, Author author) => 7 | (Title, Author) = (title, author); 8 | 9 | public static bool doesHaveDiscount(Book book) => 10 | book switch 11 | { 12 | { Author.LastName: "Richter" } 13 | or { Author.LastName: "Price" } => true, 14 | _ => false 15 | }; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /csharp10/3. Constant Interpolated Strings/Book.cs: -------------------------------------------------------------------------------- 1 | namespace _3._Constant_Interpolated_Strings; 2 | public class Book 3 | { 4 | public string Title { get; set; } 5 | public Author Author { get; set; } 6 | public Book(string title, Author author) => 7 | (Title, Author) = (title, author); 8 | 9 | public string ThankYouMessage() 10 | { 11 | const string message = "Thank you for buying the book!"; 12 | const string thankYouMessage = $"{message} Enjoy"; 13 | return thankYouMessage; 14 | } 15 | } -------------------------------------------------------------------------------- /csharp13/9. Ref Struct Interfaces/Program.cs: -------------------------------------------------------------------------------- 1 | var refStruct = new RefStruct { Value = 13 }; 2 | Console.WriteLine(refStruct.CheckIfValid()); 3 | refStruct.Value *= -1; 4 | Console.WriteLine(refStruct.CheckIfValid()); 5 | 6 | ref struct RefStruct : IRefStruct 7 | { 8 | public int Value { get; set; } 9 | public bool CheckIfValid() => Value > 0; 10 | 11 | public int DefaultImplementationMethod() => 1; 12 | } 13 | 14 | interface IRefStruct 15 | { 16 | bool CheckIfValid(); 17 | 18 | int DefaultImplementationMethod() => 1; 19 | } -------------------------------------------------------------------------------- /csharp12/2. Primary constructors/Program.cs: -------------------------------------------------------------------------------- 1 | Article article = new(0, ""); 2 | var title = article.Title; 3 | var id = article.Id; 4 | 5 | Console.ReadLine(); 6 | 7 | internal class Article(int id, string title) : Item(id) 8 | { 9 | public string Title { get; set; } = title; 10 | private readonly int id = id; 11 | 12 | public int Id => id; 13 | 14 | public Article() : this(0, string.Empty) {} 15 | 16 | public Article(string title, string author) : this(0, title) 17 | { 18 | 19 | } 20 | } 21 | 22 | internal class Item(int id); -------------------------------------------------------------------------------- /csharp13/6. Implicit Index Access/Program.cs: -------------------------------------------------------------------------------- 1 | var countdown = new TimerRemaining() 2 | { 3 | Buffer = 4 | { 5 | [^1] = 0, 6 | [^2] = 1, 7 | [^3] = 2, 8 | [^4] = 3, 9 | [^5] = 4, 10 | [^6] = 5, 11 | [^7] = 6, 12 | [^8] = 7, 13 | [^9] = 8, 14 | [^10] = 9 15 | } 16 | }; 17 | 18 | foreach (var item in countdown.Buffer) 19 | { 20 | Console.WriteLine(item); 21 | } 22 | 23 | public class TimerRemaining 24 | { 25 | public int[] Buffer { get; } = new int[10]; 26 | } 27 | -------------------------------------------------------------------------------- /csharp11/2. Generic Attributes/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace _2._Generic_Attributes 4 | { 5 | // before 6 | public class TypeAttribute : Attribute 7 | { 8 | public Type ParamType { get; } 9 | public TypeAttribute(Type t) => ParamType = t; 10 | } 11 | 12 | public class GenericType 13 | { 14 | //[TypeAttribute(typeof(string))] 15 | [GenericAttribute()] 16 | string Method() => "Test"; 17 | } 18 | 19 | // c# 11 20 | public class GenericAttribute : Attribute { } 21 | } -------------------------------------------------------------------------------- /csharp13/10. More Partial Members/Program.cs: -------------------------------------------------------------------------------- 1 | var items = new Items(); 2 | 3 | public partial class Items 4 | { 5 | public partial int Capacity { get; set; } 6 | } 7 | 8 | public partial class Items 9 | { 10 | public partial int Capacity 11 | { 12 | get => _items.Count; 13 | set 14 | { 15 | if (value != _items.Count && value >= 0) 16 | { 17 | _items.Capacity = value; 18 | } 19 | } 20 | } 21 | 22 | private readonly List _items = Enumerable.Range(0, 10).ToList(); 23 | } -------------------------------------------------------------------------------- /csharp10/5. Deconstruction/Program.cs: -------------------------------------------------------------------------------- 1 | var author = new Author("Andrei", "Fedotov"); 2 | Console.WriteLine(author); 3 | 4 | (string name1, string lastName) = author; 5 | Console.WriteLine(name1); 6 | Console.WriteLine(lastName); 7 | 8 | var name2 = string.Empty; 9 | var lastname2 = string.Empty; 10 | (name2, lastname2) = author; 11 | Console.WriteLine(name2); 12 | Console.WriteLine(lastname2); 13 | 14 | //== C# 10 feature 15 | 16 | 17 | var lastname3 = string.Empty; 18 | (var name3, lastname3) = author; 19 | Console.WriteLine(name3); 20 | Console.WriteLine(lastname3); 21 | 22 | 23 | -------------------------------------------------------------------------------- /csharp12/3. Collection expressions/Program.cs: -------------------------------------------------------------------------------- 1 | using Score = double; 2 | 3 | double[] scores = [ 5.0, 4.5 ,4.0 ]; 4 | Article article = new(1, "C# features", [ 4.8, 3 ]); 5 | var s = article.Score; 6 | Console.WriteLine(s); 7 | 8 | double[][] jagged = [[..scores, 3], [1, 2]]; 9 | 10 | 11 | Console.ReadLine(); 12 | 13 | internal class Article(int id, string title, Score[] scores) 14 | { 15 | public Article() : this(0, string.Empty, []) 16 | { 17 | } 18 | 19 | public Score Score => scores switch 20 | { 21 | [] => 0, 22 | [var score] => score, 23 | [.. var all] => all.Average() 24 | }; 25 | } -------------------------------------------------------------------------------- /csharp9/3. TargetTypedObject/Program.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace TargetTypedObject 3 | { 4 | public class Book 5 | { 6 | public string Title { get; } 7 | public string Author { get; } 8 | 9 | public Book() { } 10 | public Book(string title, string author) 11 | { 12 | Title = title; 13 | Author = author; 14 | } 15 | } 16 | class Program 17 | { 18 | static void Main() 19 | { 20 | var book = new Book("1", "2"); 21 | 22 | Book book2 = new("1", "2"); 23 | 24 | Book book3 = new(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /csharp9/5. RelationalAndLogicalPatterns/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RelationalAndLogicalPatterns 4 | { 5 | public class Book 6 | { 7 | public string Title { get; set; } 8 | public string Author { get; set; } 9 | 10 | public static decimal Postage(decimal price) => price switch 11 | { 12 | < 20 => 6.99m, 13 | >= 20 and < 40 => 3.99m, 14 | >= 40 and < 60 => 2.99m, 15 | _ => 0 16 | }; 17 | 18 | } 19 | class Program 20 | { 21 | static void Main(string[] args) 22 | { 23 | Console.WriteLine("Hello World!"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /csharp9/4. InitOnlySetters/Program.cs: -------------------------------------------------------------------------------- 1 | namespace InitOnlySetters 2 | { 3 | public class Edition 4 | { 5 | public string Title { get; set; } 6 | } 7 | public class Book 8 | { 9 | public string Title { get; init; } 10 | public string Author { get; set; } 11 | public Edition Edition { get; set; } 12 | 13 | } 14 | class Program 15 | { 16 | static void Main() 17 | { 18 | var book = new Book { Author = "1", Title = "2" }; 19 | var book1 = new Book(); 20 | System.Console.WriteLine($"Edition title: {book1.Edition.Title}"); 21 | //book.Title = "3"; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /csharp11/4. List patterns/Program.cs: -------------------------------------------------------------------------------- 1 | static int Transform(int[] values) 2 | => values switch 3 | { 4 | [1, 2, .., 10] => 1, 5 | [1, 2] => 2, 6 | [1, _] => 3, 7 | [1, ..] => 4, 8 | [..] => 50 9 | }; 10 | 11 | var array = new[] { 2, 3, 4, 5, 3, 4, 5 }; 12 | var result = Transform(array); 13 | Console.WriteLine(result); 14 | 15 | static string TransformExtra(int[] values) 16 | => values switch 17 | { 18 | [1, .., var middle, _] => $"Middle {string.Join(", ", middle)}", 19 | [3, var second, ..] => $"second = {second}", 20 | [.. var all] => $"All {string.Join(", ", all)}" 21 | }; 22 | 23 | Console.WriteLine(TransformExtra(array)); 24 | -------------------------------------------------------------------------------- /csharp9/6. ExtendedPartialMethods/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ExtendedPartialMethods 4 | { 5 | public partial class Book 6 | { 7 | public string Title { get; set; } 8 | public string Author { get; set; } 9 | 10 | public decimal Price { get; set; } 11 | 12 | private partial decimal SetPrice(); 13 | 14 | } 15 | 16 | public partial class Book 17 | { 18 | private partial decimal SetPrice() 19 | { 20 | return 0m; 21 | } 22 | } 23 | class Program 24 | { 25 | static void Main(string[] args) 26 | { 27 | Console.WriteLine("Hello World!"); 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /csharp13/2. Overload Resolution Priority/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Runtime.CompilerServices; 3 | 4 | Printer.PrintElements(["Hello", "Overload Resolution", "World"]); 5 | 6 | internal static class Printer 7 | { 8 | internal static void PrintElements(ImmutableArray elements) 9 | { 10 | foreach (var element in elements) 11 | { 12 | Console.WriteLine(element); 13 | } 14 | } 15 | 16 | [OverloadResolutionPriority(1)] 17 | internal static void PrintElements(params ReadOnlySpan elements) 18 | { 19 | foreach (var element in elements) 20 | { 21 | Console.WriteLine(element); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /csharp11/6. Generic math support/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | var numbers = new[] { 1, 2, 3 }; 4 | 5 | var sum = Sum(numbers); 6 | Console.WriteLine(sum); 7 | 8 | T Sum(T[] numbers) where T : INumber 9 | { 10 | T result = T.Zero; 11 | foreach (var n in numbers) 12 | { 13 | result += n; 14 | } 15 | return result; 16 | } 17 | 18 | 19 | //int Sum(int[] numbers) 20 | //{ 21 | // var result = 0; 22 | // foreach (var n in numbers) 23 | // { 24 | // result += n; 25 | // } 26 | // return result; 27 | //} 28 | 29 | //double SumD(double[] numbers) 30 | //{ 31 | // var result = 0.0; 32 | // foreach (var n in numbers) 33 | // { 34 | // result += n; 35 | // } 36 | // return result; 37 | //} -------------------------------------------------------------------------------- /csharp11/9. Required Properties/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | _ = new Person 4 | { 5 | FirstName = "Johny", 6 | LastName = "Gear" 7 | }; 8 | _ = new Employee("Johny", "Gear", "Secret Department"); 9 | 10 | public class Person 11 | { 12 | public required string FirstName { get; init; } 13 | public required string LastName { get; init; } 14 | public int Age { get; init; } 15 | } 16 | 17 | public class Employee : Person 18 | { 19 | public required string Department { get; init; } 20 | 21 | [SetsRequiredMembers] 22 | public Employee(string firstName, string lastName, string department) 23 | { 24 | FirstName = firstName; 25 | LastName = lastName; 26 | Department = department; 27 | } 28 | } -------------------------------------------------------------------------------- /csharp9/7. CovariantReturns/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CovariantReturns 4 | { 5 | public class Book 6 | { 7 | public string Title { get; set; } 8 | public string Author { get; set; } 9 | } 10 | 11 | public class CollectionBook : Book 12 | { 13 | public string Edition { get; set; } 14 | } 15 | 16 | public abstract class BookService 17 | { 18 | public abstract Book GetBook(); 19 | } 20 | 21 | public class CollectionBookService : BookService 22 | { 23 | public override CollectionBook GetBook() 24 | { 25 | return new CollectionBook(); 26 | } 27 | } 28 | 29 | class Program 30 | { 31 | static void Main(string[] args) 32 | { 33 | Console.WriteLine("Hello World!"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /csharp13/5. Method Group Natural Type/Program.cs: -------------------------------------------------------------------------------- 1 | /* This feature makes small optimizations to overload resolution involving method groups. 2 | Method groups are a group of methods with the same name on a type but with different parameters (overloads). 3 | Prior to C# 13 the type resolution was quite basic and you often needed to cast the method group in order to get 4 | the correct method. 5 | C# 13 takes a number of steps to remove methods that are not applicable to the scope and means the compiler is 6 | more likely to identify the correct method without additional casts. 7 | */ 8 | 9 | ResilientNotifier notifier = new ResilientNotifier(); 10 | 11 | var action8 = (Action) notifier.Notify; 12 | var action9 = notifier.Notify; 13 | 14 | class Notifier 15 | { 16 | public void Notify(string message) {} 17 | } 18 | 19 | class ResilientNotifier : Notifier 20 | { 21 | public void Notify(T data) {} 22 | } -------------------------------------------------------------------------------- /csharp13/7. Ref and Unsafe in Async and Iterators/Program.cs: -------------------------------------------------------------------------------- 1 | var c = new Calculator(); 2 | 3 | internal class Calculator 4 | { 5 | internal async Task Increment() 6 | { 7 | ref var value = ref GetValue(); 8 | await Task.Delay(1000); 9 | 10 | // not allowed 11 | // value++; 12 | 13 | // 'true' must be declared in csproj file in order to use the 'unsafe' keyword 14 | unsafe 15 | { 16 | } 17 | } 18 | 19 | private int _value = 1; 20 | private ref int GetValue() => ref _value; 21 | 22 | internal IEnumerable GetFibonacci(int maxValue) 23 | { 24 | var previous = 0; 25 | var current = 1; 26 | 27 | ref var value = ref GetValue(); 28 | while (current <= maxValue) 29 | { 30 | yield return current; 31 | 32 | // not allowed 33 | // value++; 34 | var newCurrent = previous + current; 35 | previous = current; 36 | current = newCurrent; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Фичи языка C# 2 | 3 | Здесь собраны все фичи по версиям языка `C#`, которые разбирались на канале `Platinum Dev`. 4 | Любые предложения/правки - **приветствуются**. 5 | 6 | ## Описания всех фич по версиям языка с примерами и исходниками 7 | - [C# 9](https://github.com/platinum-dev/csharp-features/tree/main/csharp9) 8 | - [C# 10](https://github.com/platinum-dev/csharp-features/tree/main/csharp10) 9 | - [C# 11](https://github.com/platinum-dev/csharp-features/tree/main/csharp11) 10 | - [C# 12](https://github.com/platinum-dev/csharp-features/tree/main/csharp12) 11 | - [C# 13](https://github.com/platinum-dev/csharp-features/tree/main/csharp13) 12 | 13 | ## Видео с разбором фич по версиям 14 | - `C# 9`: [YouTube](https://youtu.be/C506sl4T8ls) 15 | - `C# 10`: [YouTube](https://youtu.be/Gr7r2e8y298) | [Rutube](https://rutube.ru/video/b7f57091cf9668ab7bb525cdfcfb2916/) 16 | - `C# 11`: [YouTube](https://youtu.be/bMBgDGNhKME) | [Rutube](https://rutube.ru/video/0efac27cc1931bae1448d4e790fed0cd/) 17 | - `C# 12`: [YouTube](https://youtu.be/ScptPq_6geY) | [Rutube](https://rutube.ru/video/94ff9053392e56df35474c4ea84517b7/) 18 | - `C# 13`: [YouTube](https://youtu.be/gGzgn6RbfT0) | [Rutube](https://rutube.ru/video/ad5c7191fde45e62a8efc84f5bbbb01b/) 19 | -------------------------------------------------------------------------------- /csharp12/6. Ref readonly/Program.cs: -------------------------------------------------------------------------------- 1 | #region ref 2 | 3 | Data data1 = new(1); 4 | Ref(ref data1); 5 | Console.WriteLine(data1.Value); 6 | 7 | void Ref(ref Data data) 8 | { 9 | data.Value += 1; 10 | } 11 | 12 | #endregion 13 | 14 | #region out 15 | 16 | Data data2; 17 | Out(2, out data2); 18 | Console.WriteLine(data2.Value); 19 | 20 | void Out(int value, out Data data) 21 | { 22 | data = new(value); 23 | data.Value += 1; 24 | } 25 | 26 | #endregion 27 | 28 | #region in 29 | 30 | Data data3 = new(3); 31 | In(data3); 32 | In(in data3); 33 | In(ref data3); 34 | In(data3 = new Data()); 35 | 36 | void In(in Data data) 37 | { 38 | // data.Value = 1; 39 | // data.Value += 1; 40 | } 41 | 42 | #endregion 43 | 44 | #region ref readonly 45 | 46 | Data data4 = new(4); 47 | RefReadonly(data4); 48 | RefReadonly(in data4); 49 | RefReadonly(ref data4); 50 | RefReadonly(data4 = new Data()); 51 | 52 | void RefReadonly(ref readonly Data data) 53 | { 54 | // data.Value = 1; 55 | // data.Value += 1; 56 | } 57 | 58 | #endregion 59 | 60 | // // rvalue and lvalue 61 | // int x; 62 | // // ... 63 | // x = 1; 64 | // // 1 = x; 65 | // Console.WriteLine(x); 66 | 67 | 68 | struct Data(int value) 69 | { 70 | public int Value { get; set; } = value; 71 | } -------------------------------------------------------------------------------- /csharp13/3. New Lock Object/Program.cs: -------------------------------------------------------------------------------- 1 | /* 2 | namespace System.Threading 3 | { 4 | public sealed class Lock 5 | { 6 | public void Enter(); 7 | public void Exit(); 8 | public Scope EnterScope(); 9 | 10 | public ref struct Scope 11 | { 12 | public void Dispose(); 13 | } 14 | } 15 | } 16 | */ 17 | 18 | var modifier = new LockDemo(); 19 | modifier.Modify(); 20 | 21 | internal class LockDemo 22 | { 23 | private readonly Lock _lockObj = new(); 24 | 25 | public void Modify() 26 | { 27 | lock (_lockObj) 28 | { 29 | Console.WriteLine("I'm a critical section associated with _lockObj"); 30 | } 31 | 32 | using (_lockObj.EnterScope()) 33 | { 34 | Console.WriteLine("I'm another critical section associated with _lockObj"); 35 | } 36 | 37 | _lockObj.Enter(); 38 | try 39 | { 40 | Console.WriteLine("I'm also a critical section associated with _lockObj"); 41 | } 42 | finally 43 | { 44 | _lockObj.Exit(); 45 | } 46 | 47 | if (_lockObj.TryEnter()) 48 | { 49 | try 50 | { 51 | Console.WriteLine("I'm also another critical section associated with _lockObj"); 52 | } 53 | finally 54 | { 55 | _lockObj.Exit(); 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /csharp11/5. RawStringLiterals/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | 4 | string longMessage = """ 5 | This is a long message. 6 | It has several lines. 7 | Some are indented 8 | more than others. 9 | Some should start at the first column. 10 | Some have "quoted text" in them. 11 | """; 12 | 13 | var x1 = 0; 14 | var y1 = 0; 15 | var x2 = 1; 16 | var y2 = 2; 17 | 18 | var position = $$""" 19 | You are at {{{x1}}, {{y1}}} 20 | """; 21 | 22 | var json = $$$""" 23 | { 24 | "Points": [ 25 | { 26 | "X": {{{x1}}}, 27 | "Y": {{y1}} 28 | }, 29 | { 30 | "X": {{x2}}, 31 | "Y": {{y2}} 32 | } 33 | ] 34 | } 35 | """; 36 | 37 | Console.WriteLine($"JSON:\n{json}"); 38 | 39 | //Console.WriteLine(JsonSerializer.Deserialize(json)); 40 | 41 | class Point 42 | { 43 | public int X { get; set; } 44 | public int Y { get; set;} 45 | } 46 | 47 | class Root 48 | { 49 | public List Points { get; set; } 50 | public override string ToString() 51 | { 52 | var count = Points.Count; 53 | StringBuilder builder = new StringBuilder(); 54 | if (count == 0) builder.Append("No points"); 55 | else 56 | for(var i = 0; i < count; ++i) 57 | { 58 | var rect = Points[i]; 59 | builder.Append($"Point {i + 1} coordinates are: X={rect.X}, Y={rect.Y};\n"); 60 | } 61 | return builder.ToString(); 62 | } 63 | } -------------------------------------------------------------------------------- /csharp9/2. Records/Program.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Text.Json; 4 | 5 | namespace Records 6 | { 7 | //public class Book : IEquatable 8 | //{ 9 | // public string Title { get; } 10 | // public string Author { get; } 11 | 12 | // public Book(string title, string author) 13 | // { 14 | // Title = title; 15 | // Author = author; 16 | // } 17 | 18 | // public static bool operator ==(Book left, Book right) => 19 | // left is object ? left.Equals(right) : right is null; 20 | 21 | // public static bool operator !=(Book left, Book right) => !(left == right); 22 | 23 | // public override bool Equals(object obj) => obj is Book b && Equals(b); 24 | 25 | // public bool Equals(Book other) => 26 | // other is object && 27 | // Title == other.Title && 28 | // Author == other.Author; 29 | 30 | // public override int GetHashCode() => HashCode.Combine(Title, Author); 31 | //} 32 | 33 | record Book(string Title, string Author); 34 | 35 | //record Book(string Title, string Author) 36 | //{ 37 | // public string Title { get; set; } = Title; 38 | //} 39 | 40 | class Program 41 | { 42 | static void Main() 43 | { 44 | var book = new Book("Title1", "Author1"); 45 | //book.Title = "Title2"; 46 | book = book with { Title = "Title2" }; 47 | var json = JsonSerializer.Serialize(book); 48 | Console.WriteLine(json); 49 | 50 | var book2 = JsonSerializer.Deserialize(json); 51 | var isEqual = book == book2; 52 | Console.WriteLine($"book == book2: {isEqual}"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /csharp9/CSharp9Features.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30615.102 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1. TopLevelStatement", "1. TopLevelStatement\1. TopLevelStatement.csproj", "{DD2C5A42-8F6A-4B1C-94BE-2AB76B282192}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "2. Records", "2. Records\2. Records.csproj", "{9CB28CB2-53B5-4D4D-A1BF-44E28A7149F2}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "3. TargetTypedObject", "3. TargetTypedObject\3. TargetTypedObject.csproj", "{C4D8B055-D438-4A30-8E5F-BF632EBFAEE6}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "4. InitOnlySetters", "4. InitOnlySetters\4. InitOnlySetters.csproj", "{9FA00518-3157-482C-BD1B-E3F4E3FA439D}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "5. RelationalAndLogicalPatterns", "5. RelationalAndLogicalPatterns\5. RelationalAndLogicalPatterns.csproj", "{9C0CC139-6FDB-49B3-A7EB-924970331FC2}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "6. ExtendedPartialMethods", "6. ExtendedPartialMethods\6. ExtendedPartialMethods.csproj", "{506FCEFF-A3C2-4010-87ED-699758364E25}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "7. CovariantReturns", "7. CovariantReturns\7. CovariantReturns.csproj", "{D00524D9-B5C0-408D-987F-55A3103453C3}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {9CB28CB2-53B5-4D4D-A1BF-44E28A7149F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {9CB28CB2-53B5-4D4D-A1BF-44E28A7149F2}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {9CB28CB2-53B5-4D4D-A1BF-44E28A7149F2}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {9CB28CB2-53B5-4D4D-A1BF-44E28A7149F2}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {C4D8B055-D438-4A30-8E5F-BF632EBFAEE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {C4D8B055-D438-4A30-8E5F-BF632EBFAEE6}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {C4D8B055-D438-4A30-8E5F-BF632EBFAEE6}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {C4D8B055-D438-4A30-8E5F-BF632EBFAEE6}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {9FA00518-3157-482C-BD1B-E3F4E3FA439D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {9FA00518-3157-482C-BD1B-E3F4E3FA439D}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {9FA00518-3157-482C-BD1B-E3F4E3FA439D}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {9FA00518-3157-482C-BD1B-E3F4E3FA439D}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {D00524D9-B5C0-408D-987F-55A3103453C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {D00524D9-B5C0-408D-987F-55A3103453C3}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {D00524D9-B5C0-408D-987F-55A3103453C3}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {D00524D9-B5C0-408D-987F-55A3103453C3}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {9C0CC139-6FDB-49B3-A7EB-924970331FC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {9C0CC139-6FDB-49B3-A7EB-924970331FC2}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {9C0CC139-6FDB-49B3-A7EB-924970331FC2}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {9C0CC139-6FDB-49B3-A7EB-924970331FC2}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {506FCEFF-A3C2-4010-87ED-699758364E25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {506FCEFF-A3C2-4010-87ED-699758364E25}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {506FCEFF-A3C2-4010-87ED-699758364E25}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {506FCEFF-A3C2-4010-87ED-699758364E25}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {DD2C5A42-8F6A-4B1C-94BE-2AB76B282192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {DD2C5A42-8F6A-4B1C-94BE-2AB76B282192}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {DD2C5A42-8F6A-4B1C-94BE-2AB76B282192}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {DD2C5A42-8F6A-4B1C-94BE-2AB76B282192}.Release|Any CPU.Build.0 = Release|Any CPU 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | GlobalSection(ExtensibilityGlobals) = postSolution 59 | SolutionGuid = {37DDFD34-F4AD-4880-BAF2-FC10C727FCAD} 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /csharp12/csharp12-features.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34322.80 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1. Alias any type", "1. Alias any type\1. Alias any type.csproj", "{492DDA55-1418-43C9-BA45-271D3647CB11}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2. Primary constructors", "2. Primary constructors\2. Primary constructors.csproj", "{2E5831AF-CCE9-4D2F-84CA-BB31914B793A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3. Collection expressions", "3. Collection expressions\3. Collection expressions.csproj", "{04E06AC3-BC4C-4C81-94FD-12FC7ECED18A}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "4. Inline arrays", "4. Inline arrays\4. Inline arrays.csproj", "{0BDDF09B-AD6C-42A7-89ED-5605FAEF713F}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5. Default lambda parameters", "5. Default lambda parameters\5. Default lambda parameters.csproj", "{F22FF516-FF28-4034-B332-AAB71D1B1531}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6. Ref readonly", "6. Ref readonly\6. Ref readonly.csproj", "{10FBECCF-5149-4C85-93FA-7B3BBB6B06AE}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "7. Experimental attribute", "7. Experimental attribute\7. Experimental attribute.csproj", "{4986BB4E-E5E2-44CF-B2C9-D3AF62A8A858}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "8. Interceptors", "8. Interceptors\8. Interceptors.csproj", "{DBBFCC7D-0B22-497A-A81C-ADF40B7A7A2A}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {492DDA55-1418-43C9-BA45-271D3647CB11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {492DDA55-1418-43C9-BA45-271D3647CB11}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {492DDA55-1418-43C9-BA45-271D3647CB11}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {492DDA55-1418-43C9-BA45-271D3647CB11}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {2E5831AF-CCE9-4D2F-84CA-BB31914B793A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {2E5831AF-CCE9-4D2F-84CA-BB31914B793A}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {2E5831AF-CCE9-4D2F-84CA-BB31914B793A}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {2E5831AF-CCE9-4D2F-84CA-BB31914B793A}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {04E06AC3-BC4C-4C81-94FD-12FC7ECED18A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {04E06AC3-BC4C-4C81-94FD-12FC7ECED18A}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {04E06AC3-BC4C-4C81-94FD-12FC7ECED18A}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {04E06AC3-BC4C-4C81-94FD-12FC7ECED18A}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {0BDDF09B-AD6C-42A7-89ED-5605FAEF713F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {0BDDF09B-AD6C-42A7-89ED-5605FAEF713F}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {0BDDF09B-AD6C-42A7-89ED-5605FAEF713F}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {0BDDF09B-AD6C-42A7-89ED-5605FAEF713F}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {F22FF516-FF28-4034-B332-AAB71D1B1531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {F22FF516-FF28-4034-B332-AAB71D1B1531}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {F22FF516-FF28-4034-B332-AAB71D1B1531}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {F22FF516-FF28-4034-B332-AAB71D1B1531}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {10FBECCF-5149-4C85-93FA-7B3BBB6B06AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {10FBECCF-5149-4C85-93FA-7B3BBB6B06AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {10FBECCF-5149-4C85-93FA-7B3BBB6B06AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {10FBECCF-5149-4C85-93FA-7B3BBB6B06AE}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {4986BB4E-E5E2-44CF-B2C9-D3AF62A8A858}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {4986BB4E-E5E2-44CF-B2C9-D3AF62A8A858}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {4986BB4E-E5E2-44CF-B2C9-D3AF62A8A858}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {4986BB4E-E5E2-44CF-B2C9-D3AF62A8A858}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {DBBFCC7D-0B22-497A-A81C-ADF40B7A7A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {DBBFCC7D-0B22-497A-A81C-ADF40B7A7A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {DBBFCC7D-0B22-497A-A81C-ADF40B7A7A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {DBBFCC7D-0B22-497A-A81C-ADF40B7A7A2A}.Release|Any CPU.Build.0 = Release|Any CPU 60 | EndGlobalSection 61 | GlobalSection(SolutionProperties) = preSolution 62 | HideSolutionNode = FALSE 63 | EndGlobalSection 64 | GlobalSection(ExtensibilityGlobals) = postSolution 65 | SolutionGuid = {F59AF698-0D4D-4EF0-BF56-CA04BC6FBD15} 66 | EndGlobalSection 67 | EndGlobal 68 | -------------------------------------------------------------------------------- /csharp10/Csharp10.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31717.71 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "0. Console Template", "Csharp10\0. Console Template.csproj", "{3581FBF3-ED84-470A-A5AA-10083729EDF2}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "2. Extended Property Patterns", "2. Extended Property Patterns\2. Extended Property Patterns.csproj", "{A36783E3-7A5A-4505-9754-A6D5FCA88E08}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1. File-Scoped Namespace", "1. File-Scoped Namespace\1. File-Scoped Namespace.csproj", "{C0870B9F-8147-4350-B162-A26873C5FB88}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "3. Constant Interpolated Strings", "3. Constant Interpolated Strings\3. Constant Interpolated Strings.csproj", "{5096A3ED-FC8B-4B51-A5DB-D112905FFD16}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "4. Records", "4. Records\4. Records.csproj", "{3D22AB24-0FA1-4FEE-8EFF-52EF75215298}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "6. Global Using directive", "6. Global Using directive\6. Global Using directive.csproj", "{A95573D8-9646-497D-8297-168A1B0A6D4D}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5. Deconstruction", "5. Deconstruction\5. Deconstruction.csproj", "{2B94E4B5-1D1A-4E1B-9F74-750DBB1DF6BF}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "7. Structure Types", "7. Structure Types\7. Structure Types.csproj", "{756D2E42-F7AD-4A78-BC72-5A17C8A5B4D7}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {3581FBF3-ED84-470A-A5AA-10083729EDF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {3581FBF3-ED84-470A-A5AA-10083729EDF2}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {3581FBF3-ED84-470A-A5AA-10083729EDF2}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {3581FBF3-ED84-470A-A5AA-10083729EDF2}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {A36783E3-7A5A-4505-9754-A6D5FCA88E08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {A36783E3-7A5A-4505-9754-A6D5FCA88E08}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {A36783E3-7A5A-4505-9754-A6D5FCA88E08}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {A36783E3-7A5A-4505-9754-A6D5FCA88E08}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {C0870B9F-8147-4350-B162-A26873C5FB88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {C0870B9F-8147-4350-B162-A26873C5FB88}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {C0870B9F-8147-4350-B162-A26873C5FB88}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {C0870B9F-8147-4350-B162-A26873C5FB88}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {5096A3ED-FC8B-4B51-A5DB-D112905FFD16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {5096A3ED-FC8B-4B51-A5DB-D112905FFD16}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {5096A3ED-FC8B-4B51-A5DB-D112905FFD16}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {5096A3ED-FC8B-4B51-A5DB-D112905FFD16}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {3D22AB24-0FA1-4FEE-8EFF-52EF75215298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {3D22AB24-0FA1-4FEE-8EFF-52EF75215298}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {3D22AB24-0FA1-4FEE-8EFF-52EF75215298}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {3D22AB24-0FA1-4FEE-8EFF-52EF75215298}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {A95573D8-9646-497D-8297-168A1B0A6D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {A95573D8-9646-497D-8297-168A1B0A6D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {A95573D8-9646-497D-8297-168A1B0A6D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {A95573D8-9646-497D-8297-168A1B0A6D4D}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {2B94E4B5-1D1A-4E1B-9F74-750DBB1DF6BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {2B94E4B5-1D1A-4E1B-9F74-750DBB1DF6BF}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {2B94E4B5-1D1A-4E1B-9F74-750DBB1DF6BF}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {2B94E4B5-1D1A-4E1B-9F74-750DBB1DF6BF}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {756D2E42-F7AD-4A78-BC72-5A17C8A5B4D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {756D2E42-F7AD-4A78-BC72-5A17C8A5B4D7}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {756D2E42-F7AD-4A78-BC72-5A17C8A5B4D7}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {756D2E42-F7AD-4A78-BC72-5A17C8A5B4D7}.Release|Any CPU.Build.0 = Release|Any CPU 60 | EndGlobalSection 61 | GlobalSection(SolutionProperties) = preSolution 62 | HideSolutionNode = FALSE 63 | EndGlobalSection 64 | GlobalSection(ExtensibilityGlobals) = postSolution 65 | SolutionGuid = {1FCEBE69-D1F4-4898-A28B-CE5E8BB1D386} 66 | EndGlobalSection 67 | EndGlobal 68 | -------------------------------------------------------------------------------- /csharp11/Csharp11.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33110.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1. Auto Default Structs", "1. Auto Default Structs\1. Auto Default Structs.csproj", "{A80F8DC5-D759-4A8D-8240-EF3298C3461E}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2. Generic Attributes", "2. Generic Attributes\2. Generic Attributes.csproj", "{7C305DE8-B65C-4AFC-B3D3-ECBB4FCDD7FE}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3. Newlines in string interpolations", "3. Newlines in string interpolations\3. Newlines in string interpolations.csproj", "{4DB21DA8-CA21-4E75-AB2E-872345969207}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "4. List patterns", "4. List patterns\4. List patterns.csproj", "{9E196A33-29E9-48B5-92D8-EC242929AFD2}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5. Raw String Literals", "5. RawStringLiterals\5. Raw String Literals.csproj", "{FEF154BF-9844-464C-85FE-A9416DC3F547}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "7. Utf8 String Literals", "7. Utf8 String Literals\7. Utf8 String Literals.csproj", "{8C6B185B-2534-4F00-89AD-D7240836B0D2}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "8. File scoped types", "8. File scoped types\8. File scoped types.csproj", "{2270269A-C283-4E20-8F2A-285B5CA1578A}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "9. Required Properties", "9. Required Properties\9. Required Properties.csproj", "{55965E8D-1EB1-4400-84F5-0CE0CDD67DED}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6. Generic math support", "6. Generic math support\6. Generic math support.csproj", "{B569627A-C90A-4891-94E1-598DF06AD3A4}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {A80F8DC5-D759-4A8D-8240-EF3298C3461E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {A80F8DC5-D759-4A8D-8240-EF3298C3461E}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {A80F8DC5-D759-4A8D-8240-EF3298C3461E}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {A80F8DC5-D759-4A8D-8240-EF3298C3461E}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {7C305DE8-B65C-4AFC-B3D3-ECBB4FCDD7FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {7C305DE8-B65C-4AFC-B3D3-ECBB4FCDD7FE}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {7C305DE8-B65C-4AFC-B3D3-ECBB4FCDD7FE}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {7C305DE8-B65C-4AFC-B3D3-ECBB4FCDD7FE}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {4DB21DA8-CA21-4E75-AB2E-872345969207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {4DB21DA8-CA21-4E75-AB2E-872345969207}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {4DB21DA8-CA21-4E75-AB2E-872345969207}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {4DB21DA8-CA21-4E75-AB2E-872345969207}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {9E196A33-29E9-48B5-92D8-EC242929AFD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {9E196A33-29E9-48B5-92D8-EC242929AFD2}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {9E196A33-29E9-48B5-92D8-EC242929AFD2}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {9E196A33-29E9-48B5-92D8-EC242929AFD2}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {FEF154BF-9844-464C-85FE-A9416DC3F547}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {FEF154BF-9844-464C-85FE-A9416DC3F547}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {FEF154BF-9844-464C-85FE-A9416DC3F547}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {FEF154BF-9844-464C-85FE-A9416DC3F547}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {8C6B185B-2534-4F00-89AD-D7240836B0D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {8C6B185B-2534-4F00-89AD-D7240836B0D2}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {8C6B185B-2534-4F00-89AD-D7240836B0D2}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {8C6B185B-2534-4F00-89AD-D7240836B0D2}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {2270269A-C283-4E20-8F2A-285B5CA1578A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {2270269A-C283-4E20-8F2A-285B5CA1578A}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {2270269A-C283-4E20-8F2A-285B5CA1578A}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {2270269A-C283-4E20-8F2A-285B5CA1578A}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {55965E8D-1EB1-4400-84F5-0CE0CDD67DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {55965E8D-1EB1-4400-84F5-0CE0CDD67DED}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {55965E8D-1EB1-4400-84F5-0CE0CDD67DED}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {55965E8D-1EB1-4400-84F5-0CE0CDD67DED}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {B569627A-C90A-4891-94E1-598DF06AD3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {B569627A-C90A-4891-94E1-598DF06AD3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {B569627A-C90A-4891-94E1-598DF06AD3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {B569627A-C90A-4891-94E1-598DF06AD3A4}.Release|Any CPU.Build.0 = Release|Any CPU 66 | EndGlobalSection 67 | GlobalSection(SolutionProperties) = preSolution 68 | HideSolutionNode = FALSE 69 | EndGlobalSection 70 | GlobalSection(ExtensibilityGlobals) = postSolution 71 | SolutionGuid = {EB727D77-1BD2-45C9-8FCC-C8074EC549D1} 72 | EndGlobalSection 73 | EndGlobal 74 | -------------------------------------------------------------------------------- /csharp13/csharp13-features.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35327.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1. Params Collections", "1. Params Collections\1. Params Collections.csproj", "{E5265D4C-CE63-4964-A62C-CB5C2AB05A0F}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "2. Overload Resolution Priority", "2. Overload Resolution Priority\2. Overload Resolution Priority.csproj", "{8AE81BD5-6186-4CA9-BC1D-D5FA61106AA0}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "3. New Lock Object", "3. New Lock Object\3. New Lock Object.csproj", "{C154A274-21AC-47D7-A956-1F2040CDD3E6}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "4. New Escape Sequence", "4. New Escape Sequence\4. New Escape Sequence.csproj", "{B548978A-AF2A-4234-9B3E-45031B9CA348}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "5. Method Group Natural Type", "5. Method Group Natural Type\5. Method Group Natural Type.csproj", "{E12FC886-BA63-42A8-BD38-8F69BB83A9C9}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "6. Implicit Index Access", "6. Implicit Index Access\6. Implicit Index Access.csproj", "{0DB3FD80-1990-4282-A417-E3929B5D43AA}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "7. Ref and Unsafe in Async and Iterators", "7. Ref and Unsafe in Async and Iterators\7. Ref and Unsafe in Async and Iterators.csproj", "{146F2641-63E0-4324-A5C0-E591AD7F3269}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "8. Allows Ref Struct", "8. Allows Ref Struct\8. Allows Ref Struct.csproj", "{F0585CDD-51A1-4CE4-A17A-60BA6BE5A80E}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "9. Ref Struct Interfaces", "9. Ref Struct Interfaces\9. Ref Struct Interfaces.csproj", "{F8B3D277-EDA9-42D5-84FE-5A459895134D}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "10. More Partial Members", "10. More Partial Members\10. More Partial Members.csproj", "{222CDF3F-DD77-44B3-AF9C-748A9588C853}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "11. Field Keyword", "11. Field Keyword\11. Field Keyword.csproj", "{D5417659-A1A6-4F9C-9C56-85B2A112E2A7}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {E5265D4C-CE63-4964-A62C-CB5C2AB05A0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {E5265D4C-CE63-4964-A62C-CB5C2AB05A0F}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {E5265D4C-CE63-4964-A62C-CB5C2AB05A0F}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {E5265D4C-CE63-4964-A62C-CB5C2AB05A0F}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {8AE81BD5-6186-4CA9-BC1D-D5FA61106AA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {8AE81BD5-6186-4CA9-BC1D-D5FA61106AA0}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {8AE81BD5-6186-4CA9-BC1D-D5FA61106AA0}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {8AE81BD5-6186-4CA9-BC1D-D5FA61106AA0}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {C154A274-21AC-47D7-A956-1F2040CDD3E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {C154A274-21AC-47D7-A956-1F2040CDD3E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {C154A274-21AC-47D7-A956-1F2040CDD3E6}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {C154A274-21AC-47D7-A956-1F2040CDD3E6}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {B548978A-AF2A-4234-9B3E-45031B9CA348}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {B548978A-AF2A-4234-9B3E-45031B9CA348}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {B548978A-AF2A-4234-9B3E-45031B9CA348}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {B548978A-AF2A-4234-9B3E-45031B9CA348}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {E12FC886-BA63-42A8-BD38-8F69BB83A9C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {E12FC886-BA63-42A8-BD38-8F69BB83A9C9}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {E12FC886-BA63-42A8-BD38-8F69BB83A9C9}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {E12FC886-BA63-42A8-BD38-8F69BB83A9C9}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {0DB3FD80-1990-4282-A417-E3929B5D43AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {0DB3FD80-1990-4282-A417-E3929B5D43AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {0DB3FD80-1990-4282-A417-E3929B5D43AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {0DB3FD80-1990-4282-A417-E3929B5D43AA}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {146F2641-63E0-4324-A5C0-E591AD7F3269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {146F2641-63E0-4324-A5C0-E591AD7F3269}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {146F2641-63E0-4324-A5C0-E591AD7F3269}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {146F2641-63E0-4324-A5C0-E591AD7F3269}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {F0585CDD-51A1-4CE4-A17A-60BA6BE5A80E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {F0585CDD-51A1-4CE4-A17A-60BA6BE5A80E}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {F0585CDD-51A1-4CE4-A17A-60BA6BE5A80E}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {F0585CDD-51A1-4CE4-A17A-60BA6BE5A80E}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {F8B3D277-EDA9-42D5-84FE-5A459895134D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {F8B3D277-EDA9-42D5-84FE-5A459895134D}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {F8B3D277-EDA9-42D5-84FE-5A459895134D}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {F8B3D277-EDA9-42D5-84FE-5A459895134D}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {222CDF3F-DD77-44B3-AF9C-748A9588C853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {222CDF3F-DD77-44B3-AF9C-748A9588C853}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {222CDF3F-DD77-44B3-AF9C-748A9588C853}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {222CDF3F-DD77-44B3-AF9C-748A9588C853}.Release|Any CPU.Build.0 = Release|Any CPU 74 | {D5417659-A1A6-4F9C-9C56-85B2A112E2A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 75 | {D5417659-A1A6-4F9C-9C56-85B2A112E2A7}.Debug|Any CPU.Build.0 = Debug|Any CPU 76 | {D5417659-A1A6-4F9C-9C56-85B2A112E2A7}.Release|Any CPU.ActiveCfg = Release|Any CPU 77 | {D5417659-A1A6-4F9C-9C56-85B2A112E2A7}.Release|Any CPU.Build.0 = Release|Any CPU 78 | EndGlobalSection 79 | GlobalSection(SolutionProperties) = preSolution 80 | HideSolutionNode = FALSE 81 | EndGlobalSection 82 | EndGlobal 83 | -------------------------------------------------------------------------------- /csharp9/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Список фич C# 9 2 | 3 | ## Top-level statements 4 | 5 | Самая простая программа на C# выглядит так 6 | 7 | ```c# 8 | using System; 9 | namespace HelloWorld 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | Console.WriteLine("Hello World!"); 16 | } 17 | } 18 | } 19 | ``` 20 | 21 | но в C# 9 мы можем ещё больше упростить её: 22 | 23 | ```c# 24 | System.Console.WriteLine("Hello World!"); 25 | ``` 26 | 27 | ## Target-Typed Object Creation 28 | 29 | Рассмотрим класс: 30 | 31 | ```c# 32 | public class Book 33 | { 34 | public string Title { get; set; } 35 | public string Author { get; set; } 36 | 37 | public Book() 38 | { 39 | 40 | } 41 | 42 | public Book(string title, string author) 43 | { 44 | Title = title; 45 | Author = author; 46 | } 47 | } 48 | ``` 49 | 50 | Обычно мы создаем объекты так: 51 | 52 | ```c# 53 | var book = new Book(); 54 | // or 55 | Book book = new Book(); 56 | ``` 57 | 58 | Теперь можно и так: 59 | 60 | ```c# 61 | Book book2 = new(); 62 | Book book3 = new("1", "A1"); 63 | ``` 64 | 65 | ## Init-only Setters 66 | 67 | Рассмотрим класс `Book` 68 | 69 | ```c# 70 | public class Book 71 | { 72 | public string Title { get; set; } 73 | public string Author { get; set; } 74 | } 75 | ``` 76 | 77 | и мы можем инициализировать поля во время создания объекта. А также мы можем их менять потом, так как у нас есть сеттер. 78 | 79 | ```c# 80 | var book = new Book { Author = "1", Title = "2" }; 81 | book.Title = "2"; 82 | ``` 83 | А что если мы хотим установить значение поля только во время инициализации и запретить менять его в дальнейшем? в `C# 9` появилась такая возможность. 84 | 85 | ```c# 86 | public class Book 87 | { 88 | public string Title { get; init; } 89 | public string Author { get; init; } 90 | } 91 | 92 | var book = new Book { Author = "1", Title = "2" }; 93 | book.Title = "2"; // compile error 94 | ``` 95 | 96 | ## Relational & Logical Patterns 97 | 98 | ```c# 99 | public class Book 100 | { 101 | public string Title { get; set; } 102 | public string Author { get; set; } 103 | 104 | public static decimal Postage(decimal price) => price switch 105 | { 106 | < 20 => 6.99m, 107 | >= 20 and < 40 => 5.99m, 108 | >= 40 and < 60 => 2.99m, 109 | _ => 0 110 | }; 111 | } 112 | ``` 113 | 114 | ## Records 115 | 116 | ```c# 117 | public class Book 118 | { 119 | public string Title { get; } 120 | public string Author { get; } 121 | 122 | public Book(string title, string author) 123 | { 124 | Title = title; 125 | Author = author; 126 | } 127 | } 128 | ``` 129 | 130 | Представим, что мы создаем объект 131 | 132 | ```c# 133 | var book = new Book("Title1", "Author1"); 134 | ``` 135 | 136 | и хотим его сериализовать и десериализовать 137 | 138 | ```c# 139 | 140 | var json = JsonSerializer.Serialize(book); 141 | Console.WriteLine(json); 142 | var book2 = JsonSerializer.Deserialize(json); 143 | var isEqual = book == book2; 144 | Console.WriteLine($"book == book2: {isEqual}"); // false 145 | 146 | ``` 147 | 148 | и увидим, что теперь это не один и тот же объект. Но как сделать так, чтобы он был тем же самым? Мы можем переопределить `==`: 149 | 150 | ```c# 151 | public static bool operator ==(Book left, Book right) => 152 | left is object ? left.Equals(right) : right is null; 153 | ``` 154 | 155 | а также нужно переопределить оператор `!=`: 156 | 157 | ```c# 158 | public static bool operator !=(Book left, Book right) => !(left == right); 159 | ``` 160 | 161 | а также метод `Equals` для сравнения объектов: 162 | 163 | ```c# 164 | public override bool Equals(object obj) => obj is Book b && Equals(b); 165 | 166 | public bool Equals(Book other) => 167 | other is object && 168 | Title == other.Title && 169 | Author == other.Author; 170 | 171 | ``` 172 | 173 | и `GetHashCode`, и `ToString` тоже. 174 | 175 | ```c# 176 | public override int GetHashCode() => HashCode.Combine(Title, Author); 177 | public override string ToString() => $"{Title} - {Author}"; 178 | ``` 179 | 180 | И еще сделать, чтобы наш класс реализовывал интерфейс `IEquatable`. 181 | 182 | ```c# 183 | public class Book : IEquatable 184 | ``` 185 | 186 | в итоге вон сколько кода: 187 | 188 | ```c# 189 | public class Book : IEquatable 190 | { 191 | public string Title { get; } 192 | public string Author { get; } 193 | 194 | public Book(string title, string author) 195 | { 196 | Title = title; 197 | Author = author; 198 | } 199 | 200 | public static bool operator ==(Book left, Book right) => 201 | left is object ? left.Equals(right) : right is null; 202 | 203 | public static bool operator !=(Book left, Book right) => !(left == right); 204 | 205 | public override bool Equals(object obj) => obj is Book b && Equals(b); 206 | 207 | public bool Equals(Book other) => 208 | other is object && 209 | Title == other.Title && 210 | Author == other.Author; 211 | 212 | public override int GetHashCode() => HashCode.Combine(Title, Author); 213 | } 214 | ``` 215 | 216 | теперь `Console.WriteLine($"book == book2: {isEqual}");` выводит`true`. 217 | 218 | Довольно много boilerplate кода. А еще, если мы добавим новое поле, то нужно будет обновить каждый метод. 219 | 220 | В `C# 9` мы можем использовать тип `record` для точно такого же поведени. Это позволяет нам сделать поведение классов таким, как если бы они были структурами. 221 | 222 | ```c# 223 | record Book(string Title, string Author) 224 | ``` 225 | 226 | 227 | 228 | ## Extended partial methods 229 | 230 | Теперь можно использовать модификатор и `return` в `partial` методах. 231 | 232 | ```c# 233 | public partial class Book 234 | { 235 | public string Title { get; set; } 236 | public string Author { get; set; } 237 | 238 | public decimal Price { get; set; } 239 | 240 | private partial decimal SetPrice(); 241 | } 242 | 243 | public partial class Book 244 | { 245 | private partial decimal SetPrice() 246 | { 247 | return 0m; 248 | } 249 | } 250 | 251 | ``` 252 | 253 | ## Covariant returns 254 | 255 | В `C# 9` мы можем возвращать класс-наследник и перегруженных методах. 256 | 257 | ```c# 258 | public class Book 259 | { 260 | public string Title { get; set; } 261 | public string Author { get; set; } 262 | } 263 | 264 | public class CollectionBook : Book 265 | { 266 | public string Edition { get; set; } 267 | } 268 | 269 | public abstract class BookService 270 | { 271 | public abstract Book GetBook(); 272 | } 273 | 274 | public class CollectionBookService : BookService 275 | { 276 | public override CollectionBook GetBook() 277 | { 278 | return new CollectionBook(); 279 | } 280 | } 281 | ``` 282 | 283 | -------------------------------------------------------------------------------- /csharp10/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Новые фичи C# 10 2 | 3 | ## File-scoped namespace declaration 4 | 5 | В C# 9 появилась фича под названием Top Level Statement. И это позволяло в файле с точкой входа в приложение не писать бойлерплейт код 6 | 7 | ```c# 8 | namespace HelloWorld 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | Console.WriteLine("Hello World!"); 15 | } 16 | } 17 | } 18 | ``` 19 | 20 | Например, для приложения Hello World стало достаточным всего одной строчки кода , вместо десяти. 21 | 22 | ```c# 23 | Console.WriteLine("Hello World!"); 24 | ``` 25 | 26 | 27 | 28 | И это было круто, однако иметь такую возможность всего в одном файле не слишком полезно, особенно в большом проекте. 29 | 30 | И в C# 10 пошли дальше, и первая фича, которую мы рассмотрим называется File-scoped namespace declaration. 31 | 32 | Давайте посмотрим на примере. У нас есть проект, в котором есть два класса. Мы видим, что класс объявлен внутри неймспейса и находится внутри скобочек. 33 | 34 | ```c# 35 | namespace _1._File_Scoped_Namespace 36 | { 37 | public class Author 38 | { 39 | public string Name { get; set; } 40 | public string LastName { get; set; } 41 | public Author(string name, string lastname) => 42 | (Name, LastName) = (name, lastname); 43 | } 44 | } 45 | ``` 46 | 47 | 48 | 49 | File-scoped namespace declaration позволяет избавиться от них и сделать код ещё элегантнее. А после указания неймспейса ставится точка с запятой как после обычной инструкции. 50 | 51 | ```c# 52 | namespace _1._File_Scoped_Namespace; 53 | public class Author 54 | { 55 | public string Name { get; set; } 56 | public string LastName { get; set; } 57 | public Author(string name, string lastname) => 58 | (Name, LastName) = (name, lastname); 59 | } 60 | ``` 61 | 62 | 63 | 64 | 65 | 66 | ## Extended property patterns 67 | 68 | Следующая фича называется Extended property patterns, которая будет очень полезной для условий с вложенными свойствами. 69 | 70 | Давайте посмотрим на это в действии. У нас есть класс Book. И мы хотим реализовать метод, который будет говорить имеется ли у книжки скидка. 71 | 72 | ```c# 73 | public static bool doesHaveDiscount(Book book) 74 | { 75 | return false; 76 | } 77 | ``` 78 | 79 | 80 | 81 | Условимся, что если фамилия автора книги соответствует определенному значению, то скидка есть, иначе нет. Напишем это условие. 82 | 83 | ```c# 84 | public static bool doesHaveDiscount(Book book) => 85 | book switch 86 | { 87 | { Author: { LastName: "Richter" } } 88 | or { Author: { LastName: "Price" } } => true, 89 | _ => false 90 | }; 91 | ``` 92 | 93 | Мы видим вложенные свойства у объекта. Теперь мы можем упростить данную конструкцию, просто обратившись к свойству через точку. 94 | 95 | ```c# 96 | public static bool doesHaveDiscount(Book book) => 97 | book switch 98 | { 99 | { Author.LastName: "Richter" } 100 | or { Author.LastName: "Price" } => true, 101 | _ => false 102 | }; 103 | ``` 104 | 105 | Это делает код более читаемым и чистым. 106 | 107 | 108 | 109 | ## Constant interpolated strings 110 | 111 | Следующая фича называется Constant interpolated strings. 112 | 113 | Интерполирование строк это очень клёво, потому что мы можем вставлять объект прямо в строку, не выходя за её пределы. 114 | 115 | ```c# 116 | public string ThankYouMessage() 117 | { 118 | return string.Empty; 119 | } 120 | ``` 121 | 122 | Объявим две переменные, что в C# 9 было вполне допустимым. И для второй строки сделаем интерполирование. 123 | 124 | ```c# 125 | var message = "Thank you for buying the book!"; 126 | var thankYouMessage = $"{message} Enjoy"; 127 | ``` 128 | 129 | В C# 10 мы можем сделать эти строки константами, потому что вполне очевидно, что их значения не собираются изменяться. 130 | 131 | ```c# 132 | public string ThankYouMessage() 133 | { 134 | const string message = "Thank you for buying the book!"; 135 | const string thankYouMessage = $"{message} Enjoy"; 136 | return thankYouMessage; 137 | } 138 | ``` 139 | 140 | 141 | 142 | ## Records 143 | 144 | Одной из новых фич, представленных в C# 9 были record'ы. В прошлом году мы подробно рассмотрели их и все другие нововведения 9-й версии в отдельном видео на нашем канале. Кратко говоря, добавление record классов принесло нам возможность делать классы иммутабельными, и вообще вести себя как структуры, например при сравнении двух классов. 145 | 146 | C# 10 идет дальше и теперь мы можем добавлять record структуры. Давайте рассмотрим структуру, которая иммутабельна. 147 | 148 | ```csharp 149 | public readonly record struct Point 150 | { 151 | public int X { get; } 152 | public int Y { get; } 153 | } 154 | ``` 155 | 156 | 157 | 158 | Теперь мы можем после имени структуры передать параметры. 159 | 160 | ```c# 161 | public readonly record struct Point(int X, int Y); 162 | ``` 163 | 164 | и избавиться от всего остального кода. 165 | 166 | 167 | 168 | Также в C# 10 мы можем добавить модификатор `sealed`, когда мы переопределяем метод `ToString()` в record типе. То есть запечатать. Запечатывание метода `ToString()` говорит компилятору - не надо создавать методы `ToString()` для всех отнаследованных record типов, используй вот этот. И компилятор так и делает. 169 | 170 | ```c# 171 | record Circle 172 | { 173 | public sealed override string ToString() 174 | { 175 | return typeof(Circle).Name; 176 | } 177 | } 178 | ``` 179 | 180 | 181 | 182 | ## Assignment and declaration in same deconstruction 183 | 184 | Следующая фича относится к деконструкции. 185 | 186 | Ранее можно было или присвоить сразу все значения во время деконструкции, или сначала их проинициализировать, а потом присвоить. 187 | 188 | ```c# 189 | internal class Author 190 | { 191 | public string Name { get; set; } 192 | public string LastName { get; set; } 193 | public Author(string name, string lastname) => 194 | (Name, LastName) = (name, lastname); 195 | 196 | public void Deconstruct(out string name, out string lastname) => 197 | (name, lastname) = (Name, LastName); 198 | 199 | public override string ToString() => 200 | $"{Name} {LastName}"; 201 | } 202 | 203 | ``` 204 | 205 | 206 | 207 | ```csharp 208 | var author = new Author("Andrei", "Fedotov"); 209 | Console.WriteLine(author); 210 | 211 | (string name1, string lastName) = author; 212 | Console.WriteLine(name1); 213 | Console.WriteLine(lastName); 214 | 215 | var name2 = string.Empty; 216 | var lastname2 = string.Empty; 217 | (name2, lastname2) = author; 218 | Console.WriteLine(name2); 219 | Console.WriteLine(lastname2); 220 | ``` 221 | 222 | C# 10.0 убирает ограничение предыдущей версии языка. 223 | 224 | ```csharp 225 | var lastname3 = string.Empty; 226 | (var name3, lastname2) = author; 227 | Console.WriteLine(name2); 228 | Console.WriteLine(lastname2); 229 | ``` 230 | 231 | 232 | 233 | ## Global using directives 234 | 235 | Ещё одна фича называется Global using directives. 236 | 237 | Если вас раздражает импортировать одни и те же директивы в каждом файле в приложении, то эта фича для вас. C# 10 позволяет пометить импорты как глобальные, и они будут автоматически импортированы во все файлы приложения. 238 | 239 | 240 | 241 | ```c# 242 | global using System.Collections.Generic; 243 | global using System.Linq; 244 | ``` 245 | 246 | 247 | 248 | ```c# 249 | namespace _6._Global_Using_directive; 250 | public class Store 251 | { 252 | private readonly IEnumerable Books; 253 | public Store(IEnumerable books) => Books = books; 254 | public IEnumerable GetBooks(Author author) => 255 | Books.Where(b => b.Author.LastName == author.LastName); 256 | } 257 | ``` 258 | 259 | Более того. В конфигурации проекта можно выставить специальный параметр, и тогда даже глобальные юзинги можно не прописывать. 260 | 261 | ```xml 262 | enable 263 | ``` 264 | 265 | 266 | 267 | ## Improvements of structure types 268 | 269 | Начиная с C# 10.0 мы можем объявлять конструктор без параметров для структур. 270 | 271 | 272 | 273 | ```c# 274 | public struct Point 275 | { 276 | public Point() 277 | { 278 | X = double.NaN; 279 | Y = double.NaN; 280 | } 281 | public Point(double x, double y) => 282 | (X, Y) = (x, y); 283 | 284 | public double X { get; set; } 285 | public double Y { get; set; } 286 | 287 | public override string ToString() => 288 | $"X: {X}, Y: {Y}"; 289 | } 290 | 291 | ``` 292 | 293 | Будем выводить значения для разных способов объявления экземпляров структур. 294 | 295 | ```c# 296 | var point = new Point(1,2); 297 | Console.WriteLine(point); 298 | 299 | var point2 = new Point(); 300 | Console.WriteLine(point2); 301 | 302 | var point3 = default(Point); 303 | Console.WriteLine(point3); 304 | 305 | ``` 306 | 307 | Как видим, default игнорирует конструктор без параметров и выдает дефолтное значение для типа. -------------------------------------------------------------------------------- /csharp11/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Новые фичи C# 11 2 | 3 | ## Auto default structs 4 | 5 | Представим, что у нас есть readonly структура с авто свойствами. Компилятор C# 11 гарантирует нам, что любое поле или автоматическое свойство, не инициализированное конструктором, будет проинициализировано автоматически. 6 | 7 | В C# 10 такое бы не сработало. Только если мы полностью уберем конструктор или полностью проинициализируем все свойства. 8 | 9 | ```c# 10 | readonly struct Data 11 | { 12 | public decimal Number { get; init; } 13 | public string Text { get; init; } 14 | public DateTime Date { get; init; } 15 | 16 | public Data() 17 | { 18 | Number = decimal.MinValue; 19 | Text = string.Empty; 20 | } 21 | 22 | public override string ToString() => $"Number: {Number}, Text: {Text}, Date: {Date}."; 23 | } 24 | ``` 25 | 26 | ## Generic Attributes 27 | 28 | В предыдущих версиях для этого нам нужно было бы создать конструктор, который принимает тип и присваивать его соответствующему полю в атрибуте. 29 | 30 | ```c# 31 | public class TypeAttribute : Attribute 32 | { 33 | public TypeAttribute(Type t) => ParamType = t; 34 | 35 | public Type ParamType { get; } 36 | } 37 | 38 | [TypeAttribute(typeof(string))] 39 | public string Method() => default; 40 | ``` 41 | 42 | В C# 11 мы можем создать кастомный атрибут и сделать его дженериком. То есть, создать дженерик класс, который в качестве базового класса имеет класс System.Attribute. 43 | 44 | ```c# 45 | public class GenericAttribute : Attribute { } 46 | 47 | [GenericAttribute()] 48 | public string Method() => default; 49 | ``` 50 | 51 | 52 | 53 | Эта фича предоставляет более удобный синтаксис для атрибутов, которые требуют System.Type в качестве параметра. Ранее нам нужно было создавать атрибут, который принимает Type в конструкторе. 54 | 55 | 56 | 57 | Аргументы типа должны соответствовать тем же ограничениям, что и оператор [`typeof`](https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator). Например, следующие типы не допускаются в качестве параметра типа: 58 | 59 | - `dynamic` 60 | - `string?` (или любой ссылочный тип, допускающий значение NULL) 61 | - `(int X, int Y)` (или любые другие типы кортежей, использующие синтаксис кортежей C#). 62 | 63 | Во всех случаях можно использовать базовый тип: 64 | 65 | - `object` для `dynamic`. 66 | - `string` вместо `string?`. 67 | - `ValueTuple` вместо `(int X, int Y)`. 68 | 69 | ```c# 70 | public class GenericType 71 | { 72 | [GenericAttribute()] // Not allowed! generic attributes must be fully constructed types. 73 | public string Method() => default; 74 | } 75 | ``` 76 | 77 | ## Newlines in string interpolations 78 | 79 | Когда мы интерполируем строки, то можем использовать переменные внутри наших строк. 80 | 81 | Теперь можно сделать сколько угодно переносов строк. 82 | 83 | ```c# 84 | _ = $"interpolated string with value {( 85 | test ? 86 | number1 87 | : 88 | number2 89 | )}, and some more text ..."; 90 | ``` 91 | 92 | Эта функция облегчает чтение интерполированных строк, которые используют более длинные выражения C#, такие как pattern matching в switch выражениях или запросы LINQ например. 93 | 94 | ## List Patterns 95 | 96 | List patterns расширяет pattern matching для сопоставления последовательностей элементов в списке или массиве. 97 | 98 | Представим, что у нас есть массив целых чисел и мы хотим что-то сделать в зависимости от того, что находится внутри этого массива. Мы можем сделать это разными способами, например 99 | 100 | ```c# 101 | static int Transform(int[] values) 102 | => values switch 103 | { 104 | [1, 2, .., 10] => 1, 105 | [1, 2] => 2, 106 | [1, _] => 3, 107 | [1, ..] => 4, 108 | [..] => 50 109 | }; 110 | ``` 111 | 112 | или вот, что еще можно делать теперь 113 | 114 | ```c# 115 | static string TransformExtra(int[] values) 116 | => values switch 117 | { 118 | [1, .., var middle, _] => $"Middle {string.Join(", ", middle)}", 119 | [1, var second, ..] => $"second = {second}", 120 | [.. var all] => $"All {string.Join(", ", all)}" 121 | }; 122 | ``` 123 | 124 | ## Raw String Literals 125 | 126 | Raw String Literals - это новый формат для строковых литералов. Теперь они могут содержать произвольный текст, включая пробелы, новые строки, встроенные кавычки и другие специальные символы, не требуя escape-последовательностей (или экранирования). 127 | Такой литерал начинается как минимум с трех символов двойных кавычек ("""). Таким же количеством и заканчивается. 128 | 129 | ```c# 130 | string longMessage = """ 131 | This is a long message. 132 | It has several lines. 133 | Some are indented 134 | more than others. 135 | Some should start at the first column. 136 | Some have "quoted text" in them. 137 | """; 138 | 139 | ``` 140 | 141 | 142 | 143 | Любой пробел слева от закрывающих двойных кавычек будет удален из строкового литерала. Необработанные строковые литералы можно комбинировать со строковой интерполяцией для включения фигурных скобок в выходной текст. Несколько символов $ обозначают, сколько последовательных фигурных скобок начинают и заканчивают интерполяцию 144 | 145 | ```c# 146 | var x1 = 0; 147 | var y1 = 0; 148 | var x2 = 1; 149 | var y2 = 2; 150 | 151 | var position = $$""" 152 | You are at {{{x1}}, {{y1}}} 153 | """; 154 | ``` 155 | 156 | 157 | 158 | ```c# 159 | var json = $$""" 160 | { 161 | "Points": [ 162 | { 163 | "X": {{x1}}, 164 | "Y": {{y1}} 165 | }, 166 | { 167 | "X": {{x2}}, 168 | "Y": {{y2}} 169 | } 170 | ] 171 | } 172 | """; 173 | 174 | Console.WriteLine($"JSON:\n{json}"); 175 | 176 | Console.WriteLine(JsonSerializer.Deserialize(json)); 177 | 178 | class Point 179 | { 180 | public int X { get; set; } 181 | public int Y { get; set;} 182 | } 183 | 184 | class Root 185 | { 186 | public List Points { get; set; } 187 | public override string ToString() 188 | { 189 | var count = Points.Count; 190 | StringBuilder builder = new StringBuilder(); 191 | if (count == 0) builder.Append("No points"); 192 | else 193 | for(var i = 0; i < count; ++i) 194 | { 195 | var rect = Points[i]; 196 | builder.Append($"Point {i + 1} coordinates are: X={rect.X}, Y={rect.Y};\n"); 197 | } 198 | return builder.ToString(); 199 | } 200 | } 201 | ``` 202 | 203 | 204 | 205 | ```c# 206 | var json = $$$""" 207 | { 208 | "Points": [ 209 | { 210 | "X": {{{x1}}}, 211 | "Y": {{y1}} 212 | }, 213 | { 214 | "X": {{x2}}, 215 | "Y": {{y2}} 216 | } 217 | ] 218 | } 219 | """; 220 | 221 | Console.WriteLine($"JSON:\n{json}"); 222 | 223 | // Console.WriteLine(JsonSerializer.Deserialize(json)); 224 | ``` 225 | 226 | 227 | 228 | ## Generic Math support 229 | 230 | ```c# 231 | var numbers = new[] { 1, 2, 3 }; 232 | 233 | var sum = Sum(numbers); 234 | Console.WriteLine(sum); 235 | 236 | int Sum(int[] numbers) 237 | { 238 | var result = 0; 239 | foreach (var n in numbers) 240 | { 241 | result += n; 242 | } 243 | return result; 244 | } 245 | ``` 246 | 247 | 248 | 249 | ```c# 250 | var numbers = new[] { 1, 2, 3, 0.5 }; 251 | 252 | var sum = Sum(numbers); 253 | Console.WriteLine(sum); 254 | 255 | int Sum(int[] numbers) 256 | { 257 | var result = 0; 258 | foreach (var n in numbers) 259 | { 260 | result += n; 261 | } 262 | return result; 263 | } 264 | 265 | double SumD(double[] numbers) 266 | { 267 | var result = 0.0; 268 | foreach (var n in numbers) 269 | { 270 | result += n; 271 | } 272 | return result; 273 | } 274 | ``` 275 | 276 | 277 | 278 | ```c# 279 | using System.Numerics; 280 | 281 | var numbers = new[] { 1, 2, 3, 0.5 }; 282 | 283 | var sum = Sum(numbers); 284 | Console.WriteLine(sum); 285 | 286 | T Sum(T[] numbers) where T : INumber 287 | { 288 | T result = T.Zero; 289 | foreach (var n in numbers) 290 | { 291 | result += n; 292 | } 293 | return result; 294 | } 295 | ``` 296 | 297 | 298 | 299 | ## Utf8 String Literals 300 | 301 | Вы можете указать суффикс u8 в строковом литерале, чтобы указать кодировку символов UTF-8. Упрощает создание строк UTF-8. 302 | 303 | Для read only span байтов, бинарная репрезентация строки (массив байтов символов) мы можем сделать такую же штуку. Мы добавляем u8 и это будет автоматически преобразовано в массив байтов. 304 | 305 | ```c# 306 | ReadOnlySpan value1 = new byte[12] 307 | { 308 | 72, 101, 108, 108, 111, 32, 309 | 119, 111, 114, 108, 100, 33 310 | }; 311 | 312 | ReadOnlySpan value2 = "Hello world!"u8; 313 | 314 | Console.WriteLine(Encoding.UTF8.GetString(value1)); 315 | Console.WriteLine(Encoding.UTF8.GetString(value2)); 316 | ``` 317 | 318 | ## File scoped types 319 | 320 | Было добавлено еще одно ключевое слово. Теперь мы можем создать тип, видимость которого ограничена исходным файлом, в котором он объявлен. Новая функция может быть полезна при генерации кода, чтобы избежать коллизий имен. Теперь, если мы объявляем классы в разных файлах (но в одном и том же неймспейсе), и добавим файл-модификатор к одному из них то никаких конфликтов не возникает. 321 | 322 | ```c# 323 | class Builder 324 | { 325 | } 326 | 327 | file class Builder 328 | { 329 | } 330 | ``` 331 | 332 | 333 | 334 | ## Required Properties 335 | 336 | Когда мы создаем классы или рекорды, мы можем использовать init-only. Если у нас есть куча свойств, мы можем добавить ключевое слово required, чтобы сказать компилятору, что это свойство обязательное. Если мы используем этот класс и не инициализируем свойство через конструктор или инициализатор объекта, то будет ошибка. 337 | 338 | ```c# 339 | using System.Diagnostics.CodeAnalysis; 340 | Console.WriteLine("Hello World!"); 341 | 342 | _ = new Person 343 | { 344 | FirstName = "Johny" 345 | }; 346 | _ = new Employee("Johny", "Gear", "Secret Department"); 347 | 348 | public class Person 349 | { 350 | public required string FirstName { get; init; } 351 | public required string LastName { get; init; } 352 | public int Age { get; init; } 353 | } 354 | 355 | public class Employee : Person 356 | { 357 | public required string Department { get; init; } 358 | 359 | [SetsRequiredMembers] 360 | public Employee(string firstName, string lastName, string department) 361 | { 362 | FirstName = firstName; 363 | LastName = lastName; 364 | Department = department; 365 | } 366 | } 367 | ``` 368 | 369 | -------------------------------------------------------------------------------- /csharp13/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Новые фичи C# 13 2 | 3 | ## `params collections` 4 | 5 | Само ключевое слово `params` появилось еще в версии языка 1.0. И всегда `params` параметрами должны были быть массивы. Но было бы удобно иметь возможность разработчикам также просто вызывать API, которые принимают другие типы коллекций. Например, `ReadOnlySpan` или `IEnumerable`. Особенно в тех случаях, когда компилятор может избежать неявного выделения массива с целью создания коллекции. 6 | 7 | Предыдущий релиз, C# 12, принес поддержку удобного синтаксиса создания экземпляров коллекций. Фича называлась `collection expressions`. 8 | Новая же фича `params collections` расширяет поддержку `params` для всех таких типов коллекций. 9 | 10 | Так что, разработчикам больше не нужно добавлять перегрузки для `params` которые принимают `array`, конструируют целевую коллекцию и вызывают оригинальную перегрузку с этой коллекцией, что приводило к тому, что пользователи API вынуждены были использовать дополнительное выделение памяти под массив для удобства. 11 | Вообще если честно, то я такого не видел, но ребята из Майкрософт говорят, что разработчики обычно так делали. А вы так делали? Напишите в комментариях. 12 | Пример 13 | ```csharp 14 | ReadOnlySpan text = new(["Hello", "ReadOnlySpan", "World"]); 15 | Printer.PrintElements(text); 16 | 17 | internal static class Printer 18 | { 19 | internal static void PrintElements(params ReadOnlySpan elements) 20 | { 21 | foreach (var element in elements) 22 | { 23 | Console.WriteLine(element); 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | 30 | ## Overload resolution priority 31 | Появился новый атрибут `OverloadResolutionPriorityAttribute`. Его можно использовать для предпочтения одной перегрузке другой. Авторы библиотек могут использовать этот атрибут, чтобы убедиться, что новая, улучшенная перегрузка предпочтительнее существующей перегрузки. Например, мы можем добавить новую перегрузку метода, которая более производительная существующей. И мы не хотим ломать существующий код, который использует нашу библиотеку, но мы хотели бы, чтобы пользователи получили новую версию метода после перекомпиляции. Так что, этот атрибут используется для информирования компилятора о том, какая перегрузка должна быть предпочтена. 32 | Эта функция предназначена в большей степени для авторов библиотек, чтобы избежать двусмысленности при добавлении новых перегрузок. И авторы библиотек должны быть осторожны с этим атрибутом, чтобы избежать путаницы. 33 | 34 | А мотивацией к созданию такого атрибута послужил тот факт, что авторы различных API часто попадали в ситуацию, когда для обеспечения обратной совместимости, помечали существующий устаревший метод атрибутом Obsolete навсегда. Это особенно актуально для плагинизируемых систем, где автор плагина не контролирует среду, в которой запускается плагин. И создатель среды хотел бы оставить старый метод, но заблокировать к нему доступ для нового кода. И атрибута Obsolete для этого недостаточно. Тип или метод будет виден при overload resolution и может привести к ошибкам в то время как его усовершенствованная версия уже есть, но она либо конфликтует с устаревшей версией, либо 35 | 36 | Пример: 37 | ```csharp 38 | using System.Collections.Immutable; 39 | using System.Runtime.CompilerServices; 40 | 41 | Printer.PrintElements(["Hello", "Overload Resolution", "World"]); 42 | 43 | internal static class Printer 44 | { 45 | internal static void PrintElements(ImmutableArray elements) 46 | { 47 | foreach (var element in elements) 48 | { 49 | Console.WriteLine(element); 50 | } 51 | } 52 | 53 | [OverloadResolutionPriority(1)] 54 | internal static void PrintElements(params ReadOnlySpan elements) 55 | { 56 | foreach (var element in elements) 57 | { 58 | Console.WriteLine(element); 59 | } 60 | } 61 | } 62 | ``` 63 | 64 | ## New lock object 65 | 66 | Рантайм `.NET 9` включает новый тип для синхронизации потоков - `System.Threading.Lock`. 67 | Класс `Lock` может использоваться для определения областей кода, требующих взаимоисключающего доступа между потоками процесса (обычно называемых критическими секциями) для предотвращения одновременного доступа к ресурсу. То есть это блокировка другими словами. И в нее можно входить и выходить. Поток, который входит Считается, что поток, который входит в блокировку, удерживает её до тех пор, пока не выйдет из нее. В любой момент времени блокировка может быть установлена не более чем в одном потоке. В потоке может быть несколько блокировок. Поток может вводить блокировку несколько раз, прежде чем выйти из нее, например, рекурсивно. Поток, который не может ввести блокировку немедленно, может подождать, пока блокировка не будет введена или пока не истечет указанный тайм-аут. 68 | 69 | У объекта `Lock` есть методы `Enter()` и `TryEnter()` и при их использовании стоит: 70 | - убедиться, что поток выходит из блокировки с помощью метода `Exit()` даже в случае исключений 71 | - При входе и выходе из блокировки в асинхронном методе нужно убедиться, что между входом и выходом нет ожидания. Блокировки удерживаются потоками, и код, следующий за ожиданием, может выполняться в другом потоке. 72 | 73 | Рекомендуется использовать метод `EnterScope` с конструкцией `using` или `lock`, то есть чем-то, что автоматически задиспоузит возвращаемую блокировку (объект `Lock.Scope`). 74 | 75 | Стоит отметить, что при использовании внутри ключевого слова `lock` не новый объект `Lock`, а, например, `object` или дженерик, то будет использоваться реализация блокировки на основе монитора (`System.Threading.Monitor`). 76 | 77 | Пример 78 | ```csharp 79 | var modifier = new LockDemo(); 80 | modifier.Modify(); 81 | 82 | internal class LockDemo 83 | { 84 | private readonly Lock _lockObj = new(); 85 | 86 | public void Modify() 87 | { 88 | lock (_lockObj) 89 | { 90 | Console.WriteLine("I'm a critical section associated with _lockObj"); 91 | } 92 | 93 | using (_lockObj.EnterScope()) 94 | { 95 | Console.WriteLine("I'm another critical section associated with _lockObj"); 96 | } 97 | 98 | _lockObj.Enter(); 99 | try 100 | { 101 | Console.WriteLine("I'm also a critical section associated with _lockObj"); 102 | } 103 | finally 104 | { 105 | _lockObj.Exit(); 106 | } 107 | 108 | if (_lockObj.TryEnter()) 109 | { 110 | try 111 | { 112 | Console.WriteLine("I'm also another critical section associated with _lockObj"); 113 | } 114 | finally 115 | { 116 | _lockObj.Exit(); 117 | } 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | ## New escape sequence 124 | Теперь можно использовать литерал `\e` как управляющую последовательность для символа  `ESCAPE`. Ранее для этого использовались `\u001b` или `\x1b`. 125 | Использование `\x1b` не рекомендуется, потому что если следующие за `1b` символы являются допустимыми шестнадцатеричными цифрами, то эти символы становятся частью управляющей последовательности. 126 | 127 | ## Method Group Natural Type 128 | 129 | Была добавлена оптимизация в определение перегрузки групп методов, по-английски Overload Resolution Involving Method Groups. Если у вас есть более корректный перевод, то напишите в комментариях. 130 | Method Groups это группа методов с одинаковым именем в типе, но с разными параметрами, то есть перегрузки. 131 | 132 | До C# 13 определялось всё по-простому и при необходимости нужно было делать приведение группы методов чтобы получить корректный 133 | 134 | Теперь компилятор проделывает определенную работу, для того чтобы отсеять те методы, которые точно не подойдут и чтобы можно было использовать нужный метод без дополнительного приведения. 135 | 136 | ## Implicit Index Access 137 | Неявный индекс-оператор ("с конца"), `^`, теперь может использоваться в выражениях инициализации объектов. Как в следующем примере. Кстати, этот оператор был подробно рассмотрен в одном из видео на канале ([Rutube](https://rutube.ru/video/864a544721a1393d9d7af311cc2c4c97/) и [YouTube](https://youtu.be/NWiC2xoI1z0)). 138 | 139 | Пример 140 | ```csharp 141 | var countdown = new TimerRemaining() 142 | { 143 | Buffer = 144 | { [^1] = 0, 145 | [^2] = 1, 146 | [^3] = 2, 147 | [^4] = 3, 148 | [^5] = 4, 149 | [^6] = 5, 150 | [^7] = 6, 151 | [^8] = 7, 152 | [^9] = 8, 153 | [^10] = 9 154 | } 155 | }; 156 | 157 | foreach (var item in countdown.Buffer) 158 | { 159 | Console.WriteLine(item); 160 | } 161 | 162 | public class TimerRemaining 163 | { 164 | public int[] Buffer { get; } = new int[10]; 165 | } 166 | ``` 167 | 168 | Класс `TimerRemaining` содержит массив `Buffer` длинною 10 элементов. И в примере мы присваиваем значения этому массиву от конца к началу, используя индекс-оператор. 169 | 170 | ## `ref` and `unsafe` in iterators and `async` methods 171 | 172 | Эта и следующие две фичи позволяют `ref struct` типам использовать новые конструкции. Вряд ли это пригодится, если вы используете самописные `ref struct` типы. 173 | 174 | До 13-й версии, `iterator` методы (то есть, те, которые используют `yield return`) и `async` методы не могли объявить локальные `ref` переменные, а также иметь `unsafe` контекст. 175 | 176 | В C# 13, `async` и `iterator` методы могут объявить локальные `ref` переменные, или локальные переменные типа `ref struct`. Однако эти переменные не могут быть доступны в блоке, где используется, например, `yield return`. То есть, все `yield return` и `yield break`должны быть в безопасном контексте. 177 | 178 | Пример 179 | ```csharp 180 | internal class Calculator 181 | { 182 | internal async Task Increment() 183 | { 184 | ref var value = ref GetValue(); 185 | await Task.Delay(1000); 186 | 187 | // not allowed 188 | // value++; 189 | 190 | // 'true' must be declared in csproj file in order to use the 'unsafe' keyword 191 | unsafe 192 | { 193 | } 194 | } 195 | 196 | private int _value = 1; 197 | private ref int GetValue() => ref _value; 198 | 199 | internal IEnumerable GetFibonacci(int maxValue) 200 | { 201 | var previous = 0; 202 | var current = 1; 203 | 204 | ref var value = ref GetValue(); 205 | while (current <= maxValue) 206 | { 207 | yield return current; 208 | 209 | // not allowed 210 | // value++; 211 | var newCurrent = previous + current; 212 | previous = current; 213 | current = newCurrent; 214 | } 215 | } 216 | } 217 | ``` 218 | 219 | ## `allows ref struct` 220 | До C# 13 типы `ref struct` не могли были объявлены как аргументы типа для дженерик типа или метода. Теперь можно добавить анти ограничение - `allows ref struct`, которое говорит о том, что тип аргумента может быть типом `ref struct`. Это позволяет использовать с дженерик алгоритмами такие типы как `System.Span` и `System.ReadOnlySpan`. 221 | Пример 222 | ```csharp 223 | var notifier = new Notifier>(); 224 | var notifier2 = new Notifier(); 225 | 226 | public class Notifier where T : allows ref struct 227 | { 228 | // Use T as a ref struct: 229 | public void Notify(scoped T p) 230 | { 231 | // The parameter p must follow ref safety rules 232 | } 233 | } 234 | 235 | public ref struct Data 236 | { 237 | public int Value { get; set; } 238 | } 239 | ``` 240 | 241 | ## `ref struct` interfaces 242 | Также, до C# 13 `ref struct` типам не позволялось реализовывать интерфейсы. Теперь можно. 243 | Однако, стоит помнить, что `ref struct` тип не может быть приведен к интерфейсному типу. 244 | Также, должны быть реализованы все методы, объявленные в интерфейсе, даже те, у которых есть реализация по умолчанию. Подробнее про реализацию интерфейсов по умолчанию: [Rutube](https://rutube.ru/video/ea144d753c685e19db313562b7dba38a/?r=plwd), [YouTube](https://youtu.be/gxkaVOwMRnM). 245 | 246 | Пример. 247 | ```csharp 248 | var refStruct = new RefStruct { Value = 13 }; 249 | Console.WriteLine(refStruct.CheckIfValid()); 250 | refStruct.Value *= -1; 251 | Console.WriteLine(refStruct.CheckIfValid()); 252 | 253 | ref struct RefStruct : IRefStruct 254 | { 255 | public int Value { get; set; } 256 | public bool CheckIfValid() => Value > 0; 257 | 258 | public int DefaultImplementationMethod() => 1; 259 | } 260 | 261 | interface IRefStruct 262 | { 263 | bool CheckIfValid(); 264 | 265 | int DefaultImplementationMethod() => 1; 266 | } 267 | ``` 268 | 269 | ## More partial members 270 | Теперь можно объявлять `partial` свойства и `partial` индексаторы. Здесь всё очень похоже на `partial` методы. В одном месте создаем декларацию, в другом реализацию. Сигнатуры, конечно, должны совпадать. Одно только ограничение - нельзя использовать автосвойства для реализации `partial` свойства. 271 | 272 | Пример 273 | ```csharp 274 | var items = new Items(); 275 | 276 | public partial class Items 277 | { 278 | public partial int Capacity { get; set; } 279 | } 280 | 281 | public partial class Items 282 | { 283 | public partial int Capacity 284 | { 285 | get => _items.Count; 286 | set 287 | { 288 | if (value != _items.Count && value >= 0) 289 | { 290 | _items.Capacity = value; 291 | } 292 | } 293 | } 294 | 295 | private readonly List _items = Enumerable.Range(0, 10).ToList(); 296 | } 297 | ``` 298 | 299 | ## The `field` keyword 300 | Ключевое слово `field` это превью фича. С его помощью можно не создавать отдельное приватное поле для использования в свойстве, это сделает компилятор. Фича вышла в превью потому что разработчики хотят получить обратную связь от тех, кто будет это использовать. По их мнению могут быть потенциальные breaking changes или путаница в коде в типах, где также есть поле `field`. Поживем, увидим :) 301 | 302 | Пример. 303 | 304 | ```csharp 305 | // preview must be set in csproj 306 | class TimePeriod 307 | { 308 | public double Hours { 309 | get; 310 | set => field = (value >= 0) 311 | ? value 312 | : throw new ArgumentOutOfRangeException(nameof(value), "The value must not be negative"); 313 | } 314 | } 315 | ``` 316 | 317 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,csharp,rider,dotnetcore 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,visualstudiocode,csharp,rider,dotnetcore 3 | 4 | ### Csharp ### 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Mono auto generated files 21 | mono_crash.* 22 | 23 | # Build results 24 | [Dd]ebug/ 25 | [Dd]ebugPublic/ 26 | [Rr]elease/ 27 | [Rr]eleases/ 28 | x64/ 29 | x86/ 30 | [Ww][Ii][Nn]32/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | [Ll]ogs/ 38 | 39 | # Visual Studio 2015/2017 cache/options directory 40 | .vs/ 41 | # Uncomment if you have tasks that create the project's static files in wwwroot 42 | #wwwroot/ 43 | 44 | # Visual Studio 2017 auto generated files 45 | Generated\ Files/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUnit 52 | *.VisualState.xml 53 | TestResult.xml 54 | nunit-*.xml 55 | 56 | # Build Results of an ATL Project 57 | [Dd]ebugPS/ 58 | [Rr]eleasePS/ 59 | dlldata.c 60 | 61 | # Benchmark Results 62 | BenchmarkDotNet.Artifacts/ 63 | 64 | # .NET Core 65 | project.lock.json 66 | project.fragment.lock.json 67 | artifacts/ 68 | 69 | # ASP.NET Scaffolding 70 | ScaffoldingReadMe.txt 71 | 72 | # StyleCop 73 | StyleCopReport.xml 74 | 75 | # Files built by Visual Studio 76 | *_i.c 77 | *_p.c 78 | *_h.h 79 | *.ilk 80 | *.meta 81 | *.obj 82 | *.iobj 83 | *.pch 84 | *.pdb 85 | *.ipdb 86 | *.pgc 87 | *.pgd 88 | *.rsp 89 | *.sbr 90 | *.tlb 91 | *.tli 92 | *.tlh 93 | *.tmp 94 | *.tmp_proj 95 | *_wpftmp.csproj 96 | *.log 97 | *.tlog 98 | *.vspscc 99 | *.vssscc 100 | .builds 101 | *.pidb 102 | *.svclog 103 | *.scc 104 | 105 | # Chutzpah Test files 106 | _Chutzpah* 107 | 108 | # Visual C++ cache files 109 | ipch/ 110 | *.aps 111 | *.ncb 112 | *.opendb 113 | *.opensdf 114 | *.sdf 115 | *.cachefile 116 | *.VC.db 117 | *.VC.VC.opendb 118 | 119 | # Visual Studio profiler 120 | *.psess 121 | *.vsp 122 | *.vspx 123 | *.sap 124 | 125 | # Visual Studio Trace Files 126 | *.e2e 127 | 128 | # TFS 2012 Local Workspace 129 | $tf/ 130 | 131 | # Guidance Automation Toolkit 132 | *.gpState 133 | 134 | # ReSharper is a .NET coding add-in 135 | _ReSharper*/ 136 | *.[Rr]e[Ss]harper 137 | *.DotSettings.user 138 | 139 | # TeamCity is a build add-in 140 | _TeamCity* 141 | 142 | # DotCover is a Code Coverage Tool 143 | *.dotCover 144 | 145 | # AxoCover is a Code Coverage Tool 146 | .axoCover/* 147 | !.axoCover/settings.json 148 | 149 | # Coverlet is a free, cross platform Code Coverage Tool 150 | coverage*.json 151 | coverage*.xml 152 | coverage*.info 153 | 154 | # Visual Studio code coverage results 155 | *.coverage 156 | *.coveragexml 157 | 158 | # NCrunch 159 | _NCrunch_* 160 | .*crunch*.local.xml 161 | nCrunchTemp_* 162 | 163 | # MightyMoose 164 | *.mm.* 165 | AutoTest.Net/ 166 | 167 | # Web workbench (sass) 168 | .sass-cache/ 169 | 170 | # Installshield output folder 171 | [Ee]xpress/ 172 | 173 | # DocProject is a documentation generator add-in 174 | DocProject/buildhelp/ 175 | DocProject/Help/*.HxT 176 | DocProject/Help/*.HxC 177 | DocProject/Help/*.hhc 178 | DocProject/Help/*.hhk 179 | DocProject/Help/*.hhp 180 | DocProject/Help/Html2 181 | DocProject/Help/html 182 | 183 | # Click-Once directory 184 | publish/ 185 | 186 | # Publish Web Output 187 | *.[Pp]ublish.xml 188 | *.azurePubxml 189 | # Note: Comment the next line if you want to checkin your web deploy settings, 190 | # but database connection strings (with potential passwords) will be unencrypted 191 | *.pubxml 192 | *.publishproj 193 | 194 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 195 | # checkin your Azure Web App publish settings, but sensitive information contained 196 | # in these scripts will be unencrypted 197 | PublishScripts/ 198 | 199 | # NuGet Packages 200 | *.nupkg 201 | # NuGet Symbol Packages 202 | *.snupkg 203 | # The packages folder can be ignored because of Package Restore 204 | **/[Pp]ackages/* 205 | # except build/, which is used as an MSBuild target. 206 | !**/[Pp]ackages/build/ 207 | # Uncomment if necessary however generally it will be regenerated when needed 208 | #!**/[Pp]ackages/repositories.config 209 | # NuGet v3's project.json files produces more ignorable files 210 | *.nuget.props 211 | *.nuget.targets 212 | 213 | # Microsoft Azure Build Output 214 | csx/ 215 | *.build.csdef 216 | 217 | # Microsoft Azure Emulator 218 | ecf/ 219 | rcf/ 220 | 221 | # Windows Store app package directories and files 222 | AppPackages/ 223 | BundleArtifacts/ 224 | Package.StoreAssociation.xml 225 | _pkginfo.txt 226 | *.appx 227 | *.appxbundle 228 | *.appxupload 229 | 230 | # Visual Studio cache files 231 | # files ending in .cache can be ignored 232 | *.[Cc]ache 233 | # but keep track of directories ending in .cache 234 | !?*.[Cc]ache/ 235 | 236 | # Others 237 | ClientBin/ 238 | ~$* 239 | *~ 240 | *.dbmdl 241 | *.dbproj.schemaview 242 | *.jfm 243 | *.pfx 244 | *.publishsettings 245 | orleans.codegen.cs 246 | 247 | # Including strong name files can present a security risk 248 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 249 | #*.snk 250 | 251 | # Since there are multiple workflows, uncomment next line to ignore bower_components 252 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 253 | #bower_components/ 254 | 255 | # RIA/Silverlight projects 256 | Generated_Code/ 257 | 258 | # Backup & report files from converting an old project file 259 | # to a newer Visual Studio version. Backup files are not needed, 260 | # because we have git ;-) 261 | _UpgradeReport_Files/ 262 | Backup*/ 263 | UpgradeLog*.XML 264 | UpgradeLog*.htm 265 | ServiceFabricBackup/ 266 | *.rptproj.bak 267 | 268 | # SQL Server files 269 | *.mdf 270 | *.ldf 271 | *.ndf 272 | 273 | # Business Intelligence projects 274 | *.rdl.data 275 | *.bim.layout 276 | *.bim_*.settings 277 | *.rptproj.rsuser 278 | *- [Bb]ackup.rdl 279 | *- [Bb]ackup ([0-9]).rdl 280 | *- [Bb]ackup ([0-9][0-9]).rdl 281 | 282 | # Microsoft Fakes 283 | FakesAssemblies/ 284 | 285 | # GhostDoc plugin setting file 286 | *.GhostDoc.xml 287 | 288 | # Node.js Tools for Visual Studio 289 | .ntvs_analysis.dat 290 | node_modules/ 291 | 292 | # Visual Studio 6 build log 293 | *.plg 294 | 295 | # Visual Studio 6 workspace options file 296 | *.opt 297 | 298 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 299 | *.vbw 300 | 301 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 302 | *.vbp 303 | 304 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 305 | *.dsw 306 | *.dsp 307 | 308 | # Visual Studio 6 technical files 309 | 310 | # Visual Studio LightSwitch build output 311 | **/*.HTMLClient/GeneratedArtifacts 312 | **/*.DesktopClient/GeneratedArtifacts 313 | **/*.DesktopClient/ModelManifest.xml 314 | **/*.Server/GeneratedArtifacts 315 | **/*.Server/ModelManifest.xml 316 | _Pvt_Extensions 317 | 318 | # Paket dependency manager 319 | .paket/paket.exe 320 | paket-files/ 321 | 322 | # FAKE - F# Make 323 | .fake/ 324 | 325 | # CodeRush personal settings 326 | .cr/personal 327 | 328 | # Python Tools for Visual Studio (PTVS) 329 | __pycache__/ 330 | *.pyc 331 | 332 | # Cake - Uncomment if you are using it 333 | # tools/** 334 | # !tools/packages.config 335 | 336 | # Tabs Studio 337 | *.tss 338 | 339 | # Telerik's JustMock configuration file 340 | *.jmconfig 341 | 342 | # BizTalk build output 343 | *.btp.cs 344 | *.btm.cs 345 | *.odx.cs 346 | *.xsd.cs 347 | 348 | # OpenCover UI analysis results 349 | OpenCover/ 350 | 351 | # Azure Stream Analytics local run output 352 | ASALocalRun/ 353 | 354 | # MSBuild Binary and Structured Log 355 | *.binlog 356 | 357 | # NVidia Nsight GPU debugger configuration file 358 | *.nvuser 359 | 360 | # MFractors (Xamarin productivity tool) working folder 361 | .mfractor/ 362 | 363 | # Local History for Visual Studio 364 | .localhistory/ 365 | 366 | # Visual Studio History (VSHistory) files 367 | .vshistory/ 368 | 369 | # BeatPulse healthcheck temp database 370 | healthchecksdb 371 | 372 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 373 | MigrationBackup/ 374 | 375 | # Ionide (cross platform F# VS Code tools) working folder 376 | .ionide/ 377 | 378 | # Fody - auto-generated XML schema 379 | FodyWeavers.xsd 380 | 381 | # VS Code files for those working on multiple tools 382 | .vscode/* 383 | !.vscode/settings.json 384 | !.vscode/tasks.json 385 | !.vscode/launch.json 386 | !.vscode/extensions.json 387 | *.code-workspace 388 | 389 | # Local History for Visual Studio Code 390 | .history/ 391 | 392 | # Windows Installer files from build outputs 393 | *.cab 394 | *.msi 395 | *.msix 396 | *.msm 397 | *.msp 398 | 399 | # JetBrains Rider 400 | *.sln.iml 401 | 402 | ### DotnetCore ### 403 | # .NET Core build folders 404 | bin/ 405 | obj/ 406 | 407 | # Common node modules locations 408 | /node_modules 409 | /wwwroot/node_modules 410 | 411 | ### Rider ### 412 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 413 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 414 | 415 | # User-specific stuff 416 | **/.idea 417 | .idea/**/workspace.xml 418 | .idea/**/tasks.xml 419 | .idea/**/usage.statistics.xml 420 | .idea/**/dictionaries 421 | .idea/**/shelf 422 | 423 | # AWS User-specific 424 | .idea/**/aws.xml 425 | 426 | # Generated files 427 | .idea/**/contentModel.xml 428 | 429 | # Sensitive or high-churn files 430 | .idea/**/dataSources/ 431 | .idea/**/dataSources.ids 432 | .idea/**/dataSources.local.xml 433 | .idea/**/sqlDataSources.xml 434 | .idea/**/dynamic.xml 435 | .idea/**/uiDesigner.xml 436 | .idea/**/dbnavigator.xml 437 | 438 | # Gradle 439 | .idea/**/gradle.xml 440 | .idea/**/libraries 441 | 442 | # Gradle and Maven with auto-import 443 | # When using Gradle or Maven with auto-import, you should exclude module files, 444 | # since they will be recreated, and may cause churn. Uncomment if using 445 | # auto-import. 446 | # .idea/artifacts 447 | # .idea/compiler.xml 448 | # .idea/jarRepositories.xml 449 | # .idea/modules.xml 450 | # .idea/*.iml 451 | # .idea/modules 452 | # *.iml 453 | # *.ipr 454 | 455 | # CMake 456 | cmake-build-*/ 457 | 458 | # Mongo Explorer plugin 459 | .idea/**/mongoSettings.xml 460 | 461 | # File-based project format 462 | *.iws 463 | 464 | # IntelliJ 465 | out/ 466 | 467 | # mpeltonen/sbt-idea plugin 468 | .idea_modules/ 469 | 470 | # JIRA plugin 471 | atlassian-ide-plugin.xml 472 | 473 | # Cursive Clojure plugin 474 | .idea/replstate.xml 475 | 476 | # SonarLint plugin 477 | .idea/sonarlint/ 478 | 479 | # Crashlytics plugin (for Android Studio and IntelliJ) 480 | com_crashlytics_export_strings.xml 481 | crashlytics.properties 482 | crashlytics-build.properties 483 | fabric.properties 484 | 485 | # Editor-based Rest Client 486 | .idea/httpRequests 487 | 488 | # Android studio 3.1+ serialized cache file 489 | .idea/caches/build_file_checksums.ser 490 | 491 | ### VisualStudioCode ### 492 | !.vscode/*.code-snippets 493 | 494 | # Local History for Visual Studio Code 495 | 496 | # Built Visual Studio Code Extensions 497 | *.vsix 498 | 499 | ### VisualStudioCode Patch ### 500 | # Ignore all local history of files 501 | .history 502 | .ionide 503 | 504 | ### VisualStudio ### 505 | 506 | # User-specific files 507 | 508 | # User-specific files (MonoDevelop/Xamarin Studio) 509 | 510 | # Mono auto generated files 511 | 512 | # Build results 513 | 514 | # Visual Studio 2015/2017 cache/options directory 515 | # Uncomment if you have tasks that create the project's static files in wwwroot 516 | 517 | # Visual Studio 2017 auto generated files 518 | 519 | # MSTest test Results 520 | 521 | # NUnit 522 | 523 | # Build Results of an ATL Project 524 | 525 | # Benchmark Results 526 | 527 | # .NET Core 528 | 529 | # ASP.NET Scaffolding 530 | 531 | # StyleCop 532 | 533 | # Files built by Visual Studio 534 | 535 | # Chutzpah Test files 536 | 537 | # Visual C++ cache files 538 | 539 | # Visual Studio profiler 540 | 541 | # Visual Studio Trace Files 542 | 543 | # TFS 2012 Local Workspace 544 | 545 | # Guidance Automation Toolkit 546 | 547 | # ReSharper is a .NET coding add-in 548 | 549 | # TeamCity is a build add-in 550 | 551 | # DotCover is a Code Coverage Tool 552 | 553 | # AxoCover is a Code Coverage Tool 554 | 555 | # Coverlet is a free, cross platform Code Coverage Tool 556 | 557 | # Visual Studio code coverage results 558 | 559 | # NCrunch 560 | 561 | # MightyMoose 562 | 563 | # Web workbench (sass) 564 | 565 | # Installshield output folder 566 | 567 | # DocProject is a documentation generator add-in 568 | 569 | # Click-Once directory 570 | 571 | # Publish Web Output 572 | # Note: Comment the next line if you want to checkin your web deploy settings, 573 | # but database connection strings (with potential passwords) will be unencrypted 574 | 575 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 576 | # checkin your Azure Web App publish settings, but sensitive information contained 577 | # in these scripts will be unencrypted 578 | 579 | # NuGet Packages 580 | # NuGet Symbol Packages 581 | # The packages folder can be ignored because of Package Restore 582 | # except build/, which is used as an MSBuild target. 583 | # Uncomment if necessary however generally it will be regenerated when needed 584 | # NuGet v3's project.json files produces more ignorable files 585 | 586 | # Microsoft Azure Build Output 587 | 588 | # Microsoft Azure Emulator 589 | 590 | # Windows Store app package directories and files 591 | 592 | # Visual Studio cache files 593 | # files ending in .cache can be ignored 594 | # but keep track of directories ending in .cache 595 | 596 | # Others 597 | 598 | # Including strong name files can present a security risk 599 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 600 | 601 | # Since there are multiple workflows, uncomment next line to ignore bower_components 602 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 603 | 604 | # RIA/Silverlight projects 605 | 606 | # Backup & report files from converting an old project file 607 | # to a newer Visual Studio version. Backup files are not needed, 608 | # because we have git ;-) 609 | 610 | # SQL Server files 611 | 612 | # Business Intelligence projects 613 | 614 | # Microsoft Fakes 615 | 616 | # GhostDoc plugin setting file 617 | 618 | # Node.js Tools for Visual Studio 619 | 620 | # Visual Studio 6 build log 621 | 622 | # Visual Studio 6 workspace options file 623 | 624 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 625 | 626 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 627 | 628 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 629 | 630 | # Visual Studio 6 technical files 631 | 632 | # Visual Studio LightSwitch build output 633 | 634 | # Paket dependency manager 635 | 636 | # FAKE - F# Make 637 | 638 | # CodeRush personal settings 639 | 640 | # Python Tools for Visual Studio (PTVS) 641 | 642 | # Cake - Uncomment if you are using it 643 | # tools/** 644 | # !tools/packages.config 645 | 646 | # Tabs Studio 647 | 648 | # Telerik's JustMock configuration file 649 | 650 | # BizTalk build output 651 | 652 | # OpenCover UI analysis results 653 | 654 | # Azure Stream Analytics local run output 655 | 656 | # MSBuild Binary and Structured Log 657 | 658 | # NVidia Nsight GPU debugger configuration file 659 | 660 | # MFractors (Xamarin productivity tool) working folder 661 | 662 | # Local History for Visual Studio 663 | 664 | # Visual Studio History (VSHistory) files 665 | 666 | # BeatPulse healthcheck temp database 667 | 668 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 669 | 670 | # Ionide (cross platform F# VS Code tools) working folder 671 | 672 | # Fody - auto-generated XML schema 673 | 674 | # VS Code files for those working on multiple tools 675 | 676 | # Local History for Visual Studio Code 677 | 678 | # Windows Installer files from build outputs 679 | 680 | # JetBrains Rider 681 | 682 | ### VisualStudio Patch ### 683 | # Additional files built by Visual Studio 684 | 685 | # End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,csharp,rider,dotnetcore 686 | -------------------------------------------------------------------------------- /csharp12/ReadMe.md: -------------------------------------------------------------------------------- 1 | ## Псевдоним любого типа (Alias any type) 2 | 3 | Как и ребята из презентации, начнем с простых вещей. Первая фича, которую мы рассмотрим, называется - Alias any type, или псевдоним любого типа. 4 | 5 | Теперь мы можем использовать директиву `using`, чтобы создать алиас для любого типа, а не только именованного. 6 | 7 | Например, мы можем написать вот так: 8 | 9 | ```c# 10 | using Dec = decimal; // вместо System.Decimal 11 | using SomethingAbstract = (string, decimal); 12 | using Grade = (string Course, decimal Value); 13 | ``` 14 | 15 | Мы можем попробовать использовать указатель 16 | 17 | ```c# 18 | using Grade = decimal*; 19 | ``` 20 | 21 | Но тогда получим ошибку, в принципе мы и раньше ее получили бы. А теперь можно указать что это unsafe контекст и это будет работать 22 | 23 | ```c# 24 | using unsafe Gradle = decimal*; 25 | ``` 26 | 27 | (только для этого также нужно разрешить `unsafe` контекст в настройках проекта): 28 | 29 | ```xml 30 | true 31 | ``` 32 | 33 | Может возникнуть вопрос - зачем это нужно. Основная цель, которую преследовали разработчики на этапе проектирования заключается в том, что на протяжение многих лет в C# можно было объявлять алиасы для неймспейсов и именованных типов, то есть для классов, структур, интерфейсов, рекордов. И это предоставляло инструмент для объявления неконфликтующих имен в случаях, когда имена из разных неймспейсов были одинаковые. Наверное каждый видел такую ошибку где написано, что ambiguous reference, сделайте что-нибудь. И мы могли объявить алиас. 34 | 35 | В то же время, появление в языке новых сложных конструкций привело к тому, что алиасы могли бы быть полезными, но использовать их нельзя. То есть например такие конструкции как кортежи или указатели на функции часто могут иметь большие и сложные объявления, которые может быть болезненно постоянно выписывать и обременительно пытаться читать. И алиасы могут помочь в этих случаях, указав короткое имя, которое затем можно использовать вместо полных объявлений. 36 | 37 | В рамках рефакторингов проектов возможно лучше подумать о вынесении таких конструкций в отдельные классы с полями вместо алиасов для сложных типов. 38 | 39 | ## Основные или первичные конструкторы (Primary constructors) 40 | 41 | Следующая фича называется Primary consturtors, или основные, первичные конструкторы. Это возможность определить конструктор прямо в объявлении класса или структуры. Как это можно делать в`record`'ах. 42 | 43 | То есть, объявили класс и прямо рядом в скобочках написали параметры и это будет основным конструктором. Также, стоит отметить, что эти параметры будут доступны в рамках всего класса/структуры. Это можно сравнить с поведением параметров методов внутри этих методов. 44 | 45 | ```csharp 46 | internal class Article(int id, string title) 47 | { 48 | } 49 | ``` 50 | 51 | В данном случае при объявлении объекта класса не получится использовать конструктор без параметров, так как конструктор по умолчанию подменяется. 52 | 53 | Данный код приведет к ошибке: 54 | ```csharp 55 | Article article = new(); 56 | ``` 57 | 58 | Но мы можем сами объявить конструктор без параметров, если укажем ключевое слово `this` для вызова первичного конструктора. 59 | 60 | ```csharp 61 | internal class Article(int id, string title) 62 | { 63 | public Article() : this(0, string.Empty) 64 | { 65 | } 66 | } 67 | ``` 68 | 69 | Тоже самое относится и к любым другим конструкторам: 70 | 71 | ```csharp 72 | internal class Article(int id, string title) 73 | { 74 | public Article() : this(0, string.Empty) 75 | { 76 | } 77 | 78 | public Article(string title, string author) : this(0, title) 79 | { 80 | 81 | } 82 | } 83 | ``` 84 | 85 | Это может быть удобным в случае, когда мы например используем внедрение зависимостей и эти зависимости передадим в первичный конструктор - будет сильно меньше кода. 86 | 87 | Из первичного конструктора также удобно передавать параметры в конструктор базового класса, если такой есть. 88 | 89 | ```csharp 90 | internal class Article(int id, string title) : Item(id) { ... } 91 | 92 | internal class Item(int id); 93 | ``` 94 | 95 | Как мы уже упомянули ранее, параметры в первичном конструкторе не становятся свойствами, как это например происходит если мы используем `record`. 96 | 97 | ```csharp 98 | var title = article.Title; 99 | 100 | internal record Article(string Title); 101 | ``` 102 | 103 | В классах мы явно определяем свойства. И тут можем присвоить значение из конструктора например. 104 | 105 | ```csharp 106 | public string Title { get; set; } = title; 107 | ``` 108 | 109 | Мы можем захотеть сделать `readonly` свойство. 110 | 111 | ```csharp 112 | public int Id => id; 113 | ``` 114 | 115 | Это не тоже самое. В этом случае произойдет захват переменной `id` из конструктора, как, например, происходит захват переменных в лямба-методах. Компилятор посмотрит и скажет, а окей, нужно сохранить эту переменную где-то. В случае с `Title` захвата не происходит, мы присваиваем и храним значение в отдельном свойстве. Тут мы явно не храним, а обращаемся к переменной id за значением. 116 | 117 | Мы можем сделать отдельное поле, куда сохраним значение id. И теперь id уже будет ссылаться на это поле. 118 | 119 | ```csharp 120 | private readonly int id = id; 121 | public int Id => id; 122 | ``` 123 | 124 | Посмотрим еще один пример, представим у нас такой код: 125 | 126 | ```csharp 127 | public int Id => title.Length; 128 | ``` 129 | 130 | Выше мы увидим предупреждение, что параметр title и захватывается, и мы его используем для инициализации свойства. То есть дважды сохраняем одно и тоже, чего вероятно делать не планировали. Тут мы конечно тоже могли бы сделать приватное поле. 131 | 132 | Вообще, захват переменной это не плохо, просто стоит помнить об этом при написании кода более сложного, чем данный пример. 133 | 134 | Также первичные конструкторы можно трансформировать в обычные - Visual Studio и Rider имеют такую функцию на борту. 135 | 136 | ## Выражения коллекции (Collection expressions) 137 | 138 | Следующая фича называется "Выражения коллекции". 139 | 140 | Возьмем за основу предыдущий пример. 141 | 142 | В конструкторе пусть будет третий параметр - массив оценок статьи. 143 | 144 | Тут мы также используем фичу "Псевдоним любого типа". `Score` это ни что иное как `double`. 145 | 146 | ```csharp 147 | using Score = double; 148 | ``` 149 | 150 | ```csharp 151 | internal class Article(int id, string title, Score[] scores) 152 | { 153 | public Article() : this(0, string.Empty, Array.Empty()) 154 | { 155 | } 156 | } 157 | ``` 158 | 159 | В какой-то момент мы можем захотеть использовать, например, не массив, а List на входе. 160 | 161 | ```csharp 162 | internal class Article(int id, string title, List scores) 163 | ``` 164 | 165 | И что мы увидим, если поменяем? 166 | 167 | Компилятор будет ругаться, потому что у нас вроде список, а мы пытаемся обмануть его и подсунуть массив. 168 | 169 | Ну хорошо, мы просто будем использовать оператор `new()`: 170 | 171 | ```csharp 172 | Article article = new(1, "C# features", new() { 5.0, 4.5 ,4.0 }); 173 | // ... 174 | public Article() : this(0, string.Empty, new()) {} 175 | ``` 176 | 177 | Теперь, всё хорошо. А если мы вдруг захотели поменять список на неизменяемый список. Или обратно на массив 178 | 179 | ```csharp 180 | internal class Article(int id, string title, ImmutableList scores) 181 | ``` 182 | 183 | На нас опять будут ругаться. 184 | 185 | Но есть кое-что поинтереснее. C# 12 предлагает красивый способ объявления коллекций. Нам достаточно использовать квадратные скобочки. 186 | 187 | ```csharp 188 | Article article = new(1, "C# features", [ 5.0, 4.5 ,4.0 ]); 189 | // ... 190 | public Article() : this(0, string.Empty, []) {} 191 | ``` 192 | 193 | Кстати для IEnumerable такой синтаксис тоже будет работать. Очень удобно. 194 | 195 | Таким же способом можно объявлять массивы массивов: 196 | 197 | ```csharp 198 | int[][] jagged = [[1,2,3], [4,5,6]]; 199 | // === 200 | double[] scores = [ 5.0, 4.5 ,4.0 ]; 201 | Article article = new(1, "C# features", scores); 202 | double[][] jagged = [[1,2,3], [4,5,6], scores]; 203 | ``` 204 | 205 | Здесь же появился spread оператор, он же оператор расширения. С его помощью можно объединять коллекции. Операндом spread оператора является что-то, что может быть перечислено. Spread оператор оценивает каждый элемент выражения. 206 | 207 | ```csharp 208 | double[] scores = [ 5.0, 4.5 ,4.0 ]; 209 | Article article = new(1, "C# features", [..scores, 4.8, 3]); 210 | ``` 211 | 212 | Можно использовать его в шаблонах сопоставления - matching pattern 213 | 214 | ```csharp 215 | public Score Score => scores switch 216 | { 217 | [] => 0, 218 | [var score] => score, 219 | [.. var all] => all.Average() 220 | }; 221 | ``` 222 | 223 | Тут вернется ноль, если коллекция пустая, если один элемент, то его значение и вернется, а в остальных случаях посчитается среднее. 224 | 225 | ## Встроенные массивы (Inline arrays) 226 | 227 | Следующая фича называется "Встроенные массивы" и будет полезна тем, кому необходимо писать высокопроизводительный код. Изначально Майкрософт сделали это для себя, а потом сделали это публичным. 228 | 229 | Встроенные массивы позволяют разработчику создавать массив фиксированного размера в типе `struct` . 230 | 231 | Чтобы создать такую структуру, нужно пометить её атрибутом InlineArray и описать единственное поле в ней, которое будет определять тип массива. 232 | 233 | ```csharp 234 | [System.Runtime.CompilerServices.InlineArray(10)] 235 | internal struct Buffer 236 | { 237 | private int _; 238 | } 239 | ``` 240 | 241 | И далее можно пользоваться этим массивом: 242 | 243 | ```csharp 244 | var buffer = new Buffer(); 245 | for (int i = 0; i < 10; i++) 246 | { 247 | buffer[i] = i; 248 | } 249 | 250 | foreach (var i in buffer) 251 | { 252 | Console.WriteLine(i); 253 | } 254 | ``` 255 | 256 | ## Параметры лямбда выражений по умолчанию (Default lambda parameters) 257 | 258 | Следующая фича дает возможность добавить параметр по умолчанию в лямбда выражениях. Синтаксис абсолютно такой же, как если бы мы добавляли параметр по умолчанию в любой другой метод. 259 | 260 | ```csharp 261 | var setVolume = (int value = 0) => $"The volume is set to {value}"; 262 | 263 | Console.WriteLine(setVolume()); 264 | Console.WriteLine(setVolume(4)); 265 | 266 | ``` 267 | 268 | ## `ref` `readonly` параметры 269 | 270 | Следующая фича называется `ref` `readonly` параметры. 271 | 272 | Прежде чем ее рассматривать, я предлагаю освежить в памяти передачу параметров по ссылке. 273 | 274 | Предположим, у нас есть такая структура. 275 | 276 | ```c# 277 | struct Data(int value) 278 | { 279 | public int Value { get; set; } = value; 280 | } 281 | ``` 282 | 283 | при передаче структуры в качестве параметра метода передается не исходная структура а ее копия, так как значимые типы данных передаются по значению, а не по ссылке. 284 | 285 | Для передачи по ссылке мы можем использовать такие ключевые слова как `ref`, `out`, `in`. 286 | 287 | Ключевое слово `ref` мы используем и при описании параметра метода и при передаче в него аргумента. При этом аргумент должен быть проинициализирован заранее, а внутри метода мы можем его изменять 288 | 289 | ```c# 290 | Data data1 = new(1); 291 | Ref(ref data1); 292 | Console.WriteLine(data1.Value); 293 | 294 | void Ref(ref Data data) 295 | { 296 | data.Value += 1; 297 | } 298 | ``` 299 | 300 | Ключевое слово `out` мы также используем и при описании параметра метода и при передаче аргумента. Особенность тут в том, что аргумент может быть не проинициализирован, а может и проинициализирован, но вызываемый метод обязан присвоить значение параметру. И мы можем менять значение. 301 | 302 | ```c# 303 | Data data2; 304 | Out(2, out data2); 305 | Console.WriteLine(data2.Value); 306 | 307 | void Out(int value, out Data data) 308 | { 309 | data = new(value); 310 | data.Value += 1; 311 | } 312 | ``` 313 | 314 | В случае с параметрами с модификатором `in` в описании параметра метода он обязателен, при передаче аргумента необязателен. Можно для аргумента указать `ref`, но будет предупреждение, говорящее о том что в данном случае `ref` соответствует `in` и используйте пожалуйста `in`. Также можно передать выражение, например создание новой структуры. Присваивать и изменять значение внутри метода нельзя. 315 | 316 | ```c# 317 | Data data3 = new(3); 318 | In(data3); 319 | In(in data3); 320 | In(ref data3); 321 | In(data3 = new Data()); 322 | 323 | void In(in Data data) 324 | { 325 | // data.Value = 1; 326 | // data.Value += 1; 327 | } 328 | ``` 329 | 330 | C# 12 привносит еще один модификатор - `ref readonly`. 331 | 332 | Но ведь рассмотренный модификатор `in` уже позволяет передать `readonly` ссылку зачем еще и `ref readonly` сделали. 333 | 334 | Спецификация от`Microsoft` говорит примерно следующее: 335 | 336 | ``` 337 | `in` параметры допускают как lvalues, так и rvalues и могут использоваться без каких-либо аннотаций на месте вызова. Однако API, которые захватывают или возвращают ссылки из своих параметров, хотели бы запретить rvalues, а также обеспечить некоторое указание на месте вызова о том, что ссылка захватывается. параметры ref readonly идеальны в таких случаях, поскольку они предупреждают, если используются с rvalues или без каких-либо аннотаций на месте вызова. 338 | ``` 339 | 340 | Тут могут запутать такие термины как `lvalues` и `rvalues`. Поэтому кратко о том, что это такое. 341 | 342 | `lvalue` расшифровывается как locator value и представляет объект, который занимает идентифицируемое место в памяти. 343 | 344 | а `rvalue` это всё остальное, то есть выражение, которое не занимает идентифицируемое место в памяти. 345 | 346 | Вот простой пример: 347 | 348 | ```c# 349 | int value; 350 | // ... 351 | value = 1; 352 | ``` 353 | 354 | Оператор присваивания ожидает `lvalue` с левой стороны и value им является. 355 | 356 | если мы напишем: 357 | 358 | ```c# 359 | 1 = value; 360 | ``` 361 | 362 | то получим ошибку, потому что `1` это не `lvalue'. Кратко это всё. 363 | 364 | Возвращаясь к фиче, `ref` `readonly` в таком случае будет "идеальным", как это сказано в документации. Если мы передадим в качестве аргумена `data4 = new Data()`, у нас появится предупреждение. 365 | 366 | ```c# 367 | Data data4 = new(4); 368 | RefReadonly(data4); 369 | RefReadonly(in data4); 370 | RefReadonly(ref data4); 371 | RefReadonly(data4 = new Data()); 372 | 373 | void RefReadonly(ref readonly Data data) 374 | { 375 | // data.Value = 1; 376 | // data.Value += 1; 377 | } 378 | ``` 379 | 380 | А также, например есть уже существующие API которым нужны только readonly ссылки, но они используют `ref`, так как этот модификатор появился раньше модификатора `in` и поменять в коде везде `ref` на `in` это будут ломающие изменения и на уровне кода и на уровне бинарников. 381 | 382 | Также может быть, что эти уже существующие API используют `in`, но передача rvalues им не нужна. Такие API смогут перейти на использование `ref` `readonly` почти безболезненно. 383 | 384 | ## Экспериментальный атрибут (Experimental attribute) 385 | 386 | Предположим, что мы разработали какую-то потенциально опасную для продакшена фичу и почему-то выпустили ее, возможно для каких-то экспериментов. 387 | 388 | ```c# 389 | var feature = new DangerFeature(); 390 | 391 | internal class DangerFeature 392 | { 393 | } 394 | ``` 395 | 396 | На такой случай в C# 12 появился новый атрибут - `Experimental`. Принимает параметр `diagnosticsId`. Это идентификатор, который компилятор будет использовать при сообщении об использовании API, к которому применяется этот атрибут. Если мы пометим класс этим атрибутом, то при создании объекта будет ошибка компиляции, сообщающая о том, это это экспериментальная фича и она может быть изменена или удалена в будущем. Но можно настойчиво сказать компилятору, что мы будем использовать фичу с помощью `#pragma`. 397 | 398 | ```c# 399 | using System.Diagnostics.CodeAnalysis; 400 | 401 | #pragma warning disable Danger_Identifier 402 | var feature = new DangerFeature(); 403 | #pragma warning restore Danger_Identifier 404 | 405 | [Experimental("Danger_Identifier")] 406 | internal class DangerFeature 407 | { 408 | } 409 | ``` 410 | 411 | ## Перехватчики (Interceptors) 412 | 413 | Последняя фича является экспериментальной и называется Interceptors или перехватчики. 414 | 415 | Рассмотрим на примере. 416 | 417 | У нас есть класс отправителя сообщений и всё что он делает это отправляет сообщение - в нашем случае приветствует всех в консоли. 418 | 419 | ```c# 420 | public class Sender 421 | { 422 | public void SendMessage() 423 | { 424 | Console.WriteLine("Hello everyone!"); 425 | } 426 | } 427 | ``` 428 | 429 | Создадим объект отправителя и отправим сообщение: 430 | ```c# 431 | var sender = new Sender(); 432 | sender.SendMessage(); 433 | ``` 434 | 435 | Программа выведет в консоль текст "Hello everyone!". 436 | 437 | Теперь создадим класс-перехватчик, назовем его хакером. Класс должен быть статическим и в нем мы добавляем метод расширения для класса отправителя. И выведем в консоль, что вы были взломаны. 438 | 439 | ```c# 440 | public static class Hacker 441 | { 442 | public static void InterceptMessage(this Sender sender) 443 | { 444 | Console.WriteLine("You're hacked"); 445 | } 446 | } 447 | ``` 448 | 449 | Для того, чтобы перехватчик заработал, нужно добавить атрибут. Но помимо этого, нам самим нужно еще и объявить его в отдельном файле. 450 | 451 | ```c# 452 | namespace System.Runtime.CompilerServices 453 | { 454 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 455 | sealed class InterceptsLocationAttribute(string filePath, int line, int column) : Attribute 456 | { 457 | } 458 | } 459 | ``` 460 | 461 | Далее нужно в csproj файле включить экспериментальную фичу, указав namespace, где лежит перехватчик, в нашем случае класс хакера. 462 | 463 | ```xml 464 | $(InterceptorsPreviewNamespaces);HackerSpace 465 | ``` 466 | 467 | Теперь мы можем использовать этот атрибут. В параметрах нужно указать путь до файла, где метод вызывается, строку и столбец. 468 | 469 | Запустим и увидим сообщение: "You're hacked" вместо "Hello everyone". 470 | 471 | Вероятно это не та фича, которой мы можем захотеть пользоваться регулярно и подойдет она больше в сфере кодогенерации. --------------------------------------------------------------------------------