C#

Личный сайт Go-разработчика из Казани

C# is an elegant and type-safe object-oriented language that enables developers to build a variety of secure and robust applications that run on the cross-platform .NET framework.

Read more here.

1// Single-line comments start with // 2 3/* 4Multi-line comments look like this 5*/ 6 7/// <summary> 8/// This is an XML documentation comment which can be used to generate external 9/// documentation or provide context help within an IDE 10/// </summary> 11/// <param name="firstParam">This is some parameter documentation for firstParam</param> 12/// <returns>Information on the returned value of a function</returns> 13public void MethodOrClassOrOtherWithParsableHelp(string firstParam) { } 14 15// Specify the namespaces this source code will be using 16// The namespaces below are all part of the standard .NET Framework Class Library 17using System; 18using System.Collections.Generic; 19using System.Dynamic; 20using System.Linq; 21using System.Net; 22using System.Threading.Tasks; 23using System.IO; 24 25// But this one is not: 26using System.Data.Entity; 27// In order to be able to use it, you need to add a dll reference 28// This can be done with the NuGet package manager: `Install-Package EntityFramework` 29 30// Namespaces define scope to organize code into "packages" or "modules" 31// Using this code from another source file: using Learning.CSharp; 32 33// You can also do this in C# 10, it is called file-scoped namespaces. 34// namespace Learning.CSharp; 35 36namespace Learning.CSharp 37{ 38 // Each .cs file should at least contain a class with the same name as the file. 39 // You're allowed to do otherwise, but shouldn't for sanity. 40 public class LearnCSharp 41 { 42 // BASIC SYNTAX - skip to INTERESTING FEATURES if you have used Java or C++ before 43 public static void Syntax() 44 { 45 // Use Console.WriteLine to print lines 46 Console.WriteLine("Hello World"); 47 Console.WriteLine( 48 "Integer: " + 10 + 49 " Double: " + 3.14 + 50 " Boolean: " + true); 51 52 // To print without a new line, use Console.Write 53 Console.Write("Hello "); 54 Console.Write("World"); 55 56 /////////////////////////////////////////////////// 57 // Types & Variables 58 // 59 // Declare a variable using <type> <name> 60 /////////////////////////////////////////////////// 61 62 // Sbyte - Signed 8-bit integer 63 // (-128 <= sbyte <= 127) 64 sbyte fooSbyte = 100; 65 66 // Byte - Unsigned 8-bit integer 67 // (0 <= byte <= 255) 68 byte fooByte = 100; 69 70 // Short - 16-bit integer 71 // Signed - (-32,768 <= short <= 32,767) 72 // Unsigned - (0 <= ushort <= 65,535) 73 short fooShort = 10000; 74 ushort fooUshort = 10000; 75 76 // Integer - 32-bit integer 77 int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647) 78 uint fooUint = 1; // (0 <= uint <= 4,294,967,295) 79 80 // Long - 64-bit integer 81 long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) 82 ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615) 83 // Numbers default to being int or uint depending on size. 84 // L is used to denote that this variable value is of type long or ulong 85 86 // Double - Double-precision 64-bit IEEE 754 Floating Point 87 double fooDouble = 123.4; // Precision: 15-16 digits 88 89 // Float - Single-precision 32-bit IEEE 754 Floating Point 90 float fooFloat = 234.5f; // Precision: 7 digits 91 // f is used to denote that this variable value is of type float 92 93 // Decimal - a 128-bits data type, with more precision than other floating-point types, 94 // suited for financial and monetary calculations 95 decimal fooDecimal = 150.3m; 96 97 // Boolean - true & false 98 bool fooBoolean = true; // or false 99 100 // Char - A single 16-bit Unicode character 101 char fooChar = 'A'; 102 103 // Strings -- unlike the previous base types which are all value types, 104 // a string is a reference type. That is, you can set it to null 105 string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)"; 106 Console.WriteLine(fooString); 107 108 // You can access each character of the string with an indexer: 109 char charFromString = fooString[1]; // => 'e' 110 // Strings are immutable: you can't do fooString[1] = 'X'; 111 112 // Compare strings with current culture, ignoring case 113 string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase); 114 115 // Formatting, based on sprintf 116 string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2); 117 118 // Dates & Formatting 119 DateTime fooDate = DateTime.Now; 120 Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy")); 121 122 // Verbatim String 123 // You can use the @ symbol before a string literal to escape all characters in the string 124 string path = "C:\\Users\\User\\Desktop"; 125 string verbatimPath = @"C:\Users\User\Desktop"; 126 Console.WriteLine(path == verbatimPath); // => true 127 128 // You can split a string over two lines with the @ symbol. To escape " use "" 129 string bazString = @"Here's some stuff 130on a new line! ""Wow!"", the masses cried"; 131 132 // Use const or read-only to make a variable immutable 133 // const values are calculated at compile time 134 const int HoursWorkPerWeek = 9001; 135 136 /////////////////////////////////////////////////// 137 // Data Structures 138 /////////////////////////////////////////////////// 139 140 // Arrays - zero indexed 141 // The array size must be decided upon declaration 142 // The format for declaring an array is 143 // <datatype>[] <var name> = new <datatype>[<array size>]; 144 int[] intArray = new int[10]; 145 146 // Another way to declare & initialize an array 147 int[] y = { 9000, 1000, 1337 }; 148 149 // Indexing an array - Accessing an element 150 Console.WriteLine("intArray @ 0: " + intArray[0]); 151 // Arrays are mutable. 152 intArray[1] = 1; 153 154 // Lists 155 // Lists are used more frequently than arrays as they are more flexible 156 // The format for declaring a list is 157 // List<datatype> <var name> = new List<datatype>(); 158 List<int> intList = new List<int>(); 159 List<string> stringList = new List<string>(); 160 List<int> z = new List<int> { 9000, 1000, 1337 }; // initialize 161 // The <> are for generics - Check out the cool stuff section 162 163 // Lists don't default to a value; 164 // A value must be added before accessing the index 165 intList.Add(1); 166 Console.WriteLine("intList at 0: " + intList[0]); 167 168 // Other data structures to check out: 169 // Stack/Queue 170 // Dictionary (an implementation of a hash map) 171 // HashSet 172 // Read-only Collections 173 // Tuple (.NET 4+) 174 175 /////////////////////////////////////// 176 // Operators 177 /////////////////////////////////////// 178 Console.WriteLine("\n->Operators"); 179 180 int i1 = 1, i2 = 2; // Shorthand for multiple declarations 181 182 // Arithmetic is straightforward 183 Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3 184 185 // Modulo 186 Console.WriteLine("11%3 = " + (11 % 3)); // => 2 187 188 // Comparison operators 189 Console.WriteLine("3 == 2? " + (3 == 2)); // => false 190 Console.WriteLine("3 != 2? " + (3 != 2)); // => true 191 Console.WriteLine("3 > 2? " + (3 > 2)); // => true 192 Console.WriteLine("3 < 2? " + (3 < 2)); // => false 193 Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true 194 Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true 195 196 // Bitwise operators! 197 /* 198 ~ Unary bitwise complement 199 << Signed left shift 200 >> Signed right shift 201 & Bitwise AND 202 ^ Bitwise exclusive OR 203 | Bitwise inclusive OR 204 */ 205 206 // Incrementing 207 int i = 0; 208 Console.WriteLine("\n->Inc/Dec-rement"); 209 Console.WriteLine(i++); //Prints "0", i = 1. Post-Increment 210 Console.WriteLine(++i); //Prints "2", i = 2. Pre-Increment 211 Console.WriteLine(i--); //Prints "2", i = 1. Post-Decrement 212 Console.WriteLine(--i); //Prints "0", i = 0. Pre-Decrement 213 214 /////////////////////////////////////// 215 // Control Structures 216 /////////////////////////////////////// 217 Console.WriteLine("\n->Control Structures"); 218 219 // If statements are C-like 220 int j = 10; 221 if (j == 10) 222 { 223 Console.WriteLine("I get printed"); 224 } 225 else if (j > 10) 226 { 227 Console.WriteLine("I don't"); 228 } 229 else 230 { 231 Console.WriteLine("I also don't"); 232 } 233 234 // Ternary operators 235 // A simple if/else can be written as follows 236 // <condition> ? <true> : <false> 237 int toCompare = 17; 238 string isTrue = toCompare == 17 ? "True" : "False"; 239 240 // While loop 241 int fooWhile = 0; 242 while (fooWhile < 100) 243 { 244 // Iterated 100 times, fooWhile 0->99 245 fooWhile++; 246 } 247 248 // Do While Loop 249 int fooDoWhile = 0; 250 do 251 { 252 // Start iteration 100 times, fooDoWhile 0->99 253 if (false) 254 continue; // skip the current iteration 255 256 fooDoWhile++; 257 258 if (fooDoWhile == 50) 259 break; // breaks from the loop completely 260 261 } while (fooDoWhile < 100); 262 263 // for loop structure => for(<start_statement>; <conditional>; <step>) 264 for (int fooFor = 0; fooFor < 10; fooFor++) 265 { 266 // Iterated 10 times, fooFor 0->9 267 } 268 269 // For Each Loop 270 // foreach loop structure => foreach(<iteratorType> <iteratorName> in <enumerable>) 271 // The foreach loop loops over any object implementing IEnumerable or IEnumerable<T> 272 // All the collection types (Array, List, Dictionary...) in the .NET framework 273 // implement one or both of these interfaces. 274 // (The ToCharArray() could be removed, because a string also implements IEnumerable) 275 foreach (char character in "Hello World".ToCharArray()) 276 { 277 // Iterated over all the characters in the string 278 } 279 280 // Switch Case 281 // A switch works with byte, short, char, and int data types. 282 // It also works with enumerated types (discussed in Enum Types), 283 // the String class, and a few special classes that wrap 284 // primitive types: Character, Byte, Short, and Integer. 285 int month = 3; 286 string monthString; 287 switch (month) 288 { 289 case 1: 290 monthString = "January"; 291 break; 292 case 2: 293 monthString = "February"; 294 break; 295 case 3: 296 monthString = "March"; 297 break; 298 // You can assign more than one case to an action 299 // But you can't add an action without a break before another case 300 // (if you want to do this, you would have to explicitly add a goto case x) 301 case 6: 302 case 7: 303 case 8: 304 monthString = "Summer time!!"; 305 break; 306 default: 307 monthString = "Some other month"; 308 break; 309 } 310 311 /////////////////////////////////////// 312 // Converting Data Types And Typecasting 313 /////////////////////////////////////// 314 315 // Converting data 316 317 // Convert String To Integer 318 // this will throw a FormatException on failure 319 int.Parse("123"); // returns an integer version of "123" 320 321 // TryParse will default to the type's default value on failure 322 // in this case 0 323 int tryInt; 324 if (int.TryParse("123", out tryInt)) // Function is boolean 325 Console.WriteLine(tryInt); // 123 326 327 // Convert Integer To String 328 // The Convert class has a number of methods to facilitate conversions 329 330 // String to int 331 332 // Better 333 bool result = int.TryParse(string, out var integer) 334 int.Parse(string); 335 336 // Not recommended 337 Convert.ToString(123); 338 339 // Int to string 340 tryInt.ToString(); 341 342 // Casting 343 // Cast decimal 15 to an int 344 // and then implicitly cast to long 345 long x = (int) 15M; 346 } 347 348 /////////////////////////////////////// 349 // CLASSES - see definitions at end of file 350 /////////////////////////////////////// 351 public static void Classes() 352 { 353 // See Declaration of objects at end of file 354 355 // Use new to instantiate a class 356 Bicycle trek = new Bicycle(); 357 358 // Call object methods 359 trek.SpeedUp(3); // You should always use setter and getter methods 360 trek.Cadence = 100; 361 362 // ToString is a convention to display the value of this Object. 363 Console.WriteLine("trek info: " + trek.Info()); 364 365 // Instantiate a new Penny Farthing 366 PennyFarthing funbike = new PennyFarthing(1, 10); 367 Console.WriteLine("funbike info: " + funbike.Info()); 368 369 Console.Read(); 370 } // End main method 371 372 // Available in C# 9 and later, this is basically syntactic sugar for a class. Records are immutable*. 373 public record ARecord(string Csharp); 374 375 // CONSOLE ENTRY - A console application must have a main method as an entry point 376 public static void Main(string[] args) 377 { 378 OtherInterestingFeatures(); 379 } 380 381 // 382 // INTERESTING FEATURES 383 // 384 385 // DEFAULT METHOD SIGNATURES 386 387 public // Visibility 388 static // Allows for direct call on class without object 389 int // Return Type, 390 MethodSignatures( 391 int maxCount, // First variable, expects an int 392 int count = 0, // will default the value to 0 if not passed in 393 int another = 3, 394 params string[] otherParams // captures all other parameters passed to method 395 ) 396 { 397 return -1; 398 } 399 400 // Methods can have the same name, as long as the signature is unique 401 // A method that differs only in return type is not unique 402 public static void MethodSignatures( 403 ref int maxCount, // Pass by reference 404 out int count) 405 { 406 // the argument passed in as 'count' will hold the value of 15 outside of this function 407 count = 15; // out param must be assigned before control leaves the method 408 } 409 410 // GENERICS 411 // The classes for TKey and TValue is specified by the user calling this function. 412 // This method emulates Python's dict.setdefault() 413 public static TValue SetDefault<TKey, TValue>( 414 IDictionary<TKey, TValue> dictionary, 415 TKey key, 416 TValue defaultItem) 417 { 418 TValue result; 419 if (!dictionary.TryGetValue(key, out result)) 420 return dictionary[key] = defaultItem; 421 return result; 422 } 423 424 // You can narrow down the objects that are passed in 425 public static void IterateAndPrint<T>(T toPrint) where T: IEnumerable<int> 426 { 427 // We can iterate, since T is a IEnumerable 428 foreach (var item in toPrint) 429 // Item is an int 430 Console.WriteLine(item.ToString()); 431 } 432 433 // YIELD 434 // Usage of the "yield" keyword indicates that the method it appears in is an Iterator 435 // (this means you can use it in a foreach loop) 436 public static IEnumerable<int> YieldCounter(int limit = 10) 437 { 438 for (var i = 0; i < limit; i++) 439 yield return i; 440 } 441 442 // which you would call like this : 443 public static void PrintYieldCounterToConsole() 444 { 445 foreach (var counter in YieldCounter()) 446 Console.WriteLine(counter); 447 } 448 449 // you can use more than one "yield return" in a method 450 public static IEnumerable<int> ManyYieldCounter() 451 { 452 yield return 0; 453 yield return 1; 454 yield return 2; 455 yield return 3; 456 } 457 458 // you can also use "yield break" to stop the Iterator 459 // this method would only return half of the values from 0 to limit. 460 public static IEnumerable<int> YieldCounterWithBreak(int limit = 10) 461 { 462 for (var i = 0; i < limit; i++) 463 { 464 if (i > limit/2) yield break; 465 yield return i; 466 } 467 } 468 469 public static void OtherInterestingFeatures() 470 { 471 // OPTIONAL PARAMETERS 472 MethodSignatures(3, 1, 3, "Some", "Extra", "Strings"); 473 MethodSignatures(3, another: 3); // explicitly set a parameter, skipping optional ones 474 475 // BY REF AND OUT PARAMETERS 476 int maxCount = 0, count; // ref params must have value 477 MethodSignatures(ref maxCount, out count); 478 479 // EXTENSION METHODS 480 int i = 3; 481 i.Print(); // Defined below 482 483 // NULLABLE TYPES - great for database interaction / return values 484 // any value type (i.e. not a class) can be made nullable by suffixing a ? 485 // <type>? <var name> = <value> 486 int? nullable = null; // short hand for Nullable<int> 487 Console.WriteLine("Nullable variable: " + nullable); 488 bool hasValue = nullable.HasValue; // true if not null 489 490 // ?? is syntactic sugar for specifying default value (coalesce) 491 // in case variable is null 492 int notNullable = nullable ?? 0; // 0 493 494 // ?. is an operator for null-propagation - a shorthand way of checking for null 495 nullable?.Print(); // Use the Print() extension method if nullable isn't null 496 497 // IMPLICITLY TYPED VARIABLES - you can let the compiler work out what the type is: 498 var magic = "magic is a string, at compile time, so you still get type safety"; 499 // magic = 9; will not work as magic is a string, not an int 500 501 // GENERICS 502 // 503 var phonebook = new Dictionary<string, string>() { 504 {"Sarah", "212 555 5555"} // Add some entries to the phone book 505 }; 506 507 // Calling SETDEFAULT defined as a generic above 508 Console.WriteLine(SetDefault<string,string>(phonebook, "Shaun", "No Phone")); // No Phone 509 // nb, you don't need to specify the TKey and TValue since they can be 510 // derived implicitly 511 Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555 512 513 // LAMBDA EXPRESSIONS - allow you to write code in line 514 Func<int, int> square = (x) => x * x; // Last T item is the return value 515 Console.WriteLine(square(3)); // 9 516 517 // ERROR HANDLING - coping with an uncertain world 518 try 519 { 520 var funBike = PennyFarthing.CreateWithGears(6); 521 522 // will no longer execute because CreateWithGears throws an exception 523 string some = ""; 524 if (true) some = null; 525 some.ToLower(); // throws a NullReferenceException 526 } 527 catch (NotSupportedException) 528 { 529 Console.WriteLine("Not so much fun now!"); 530 } 531 catch (Exception ex) // catch all other exceptions 532 { 533 throw new ApplicationException("It hit the fan", ex); 534 // throw; // A rethrow that preserves the callstack 535 } 536 // catch { } // catch-all without capturing the Exception 537 finally 538 { 539 // executes after try or catch 540 } 541 542 // DISPOSABLE RESOURCES MANAGEMENT - let you handle unmanaged resources easily. 543 // Most of objects that access unmanaged resources (file handle, device contexts, etc.) 544 // implement the IDisposable interface. The using statement takes care of 545 // cleaning those IDisposable objects for you. 546 using (StreamWriter writer = new StreamWriter("log.txt")) 547 { 548 writer.WriteLine("Nothing suspicious here"); 549 // At the end of scope, resources will be released. 550 // Even if an exception is thrown. 551 } 552 553 // PARALLEL FRAMEWORK 554 // https://devblogs.microsoft.com/csharpfaq/parallel-programming-in-net-framework-4-getting-started/ 555 556 var words = new List<string> {"dog", "cat", "horse", "pony"}; 557 558 Parallel.ForEach(words, 559 new ParallelOptions() { MaxDegreeOfParallelism = 4 }, 560 word => 561 { 562 Console.WriteLine(word); 563 } 564 ); 565 566 // Running this will produce different outputs 567 // since each thread finishes at different times. 568 // Some example outputs are: 569 // cat dog horse pony 570 // dog horse pony cat 571 572 // DYNAMIC OBJECTS (great for working with other languages) 573 dynamic student = new ExpandoObject(); 574 student.FirstName = "First Name"; // No need to define class first! 575 576 // You can even add methods (returns a string, and takes in a string) 577 student.Introduce = new Func<string, string>( 578 (introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo)); 579 Console.WriteLine(student.Introduce("Beth")); 580 581 // IQUERYABLE<T> - almost all collections implement this, which gives you a lot of 582 // very useful Map / Filter / Reduce style methods 583 var bikes = new List<Bicycle>(); 584 bikes.Sort(); // Sorts the array 585 bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // Sorts based on wheels 586 var result = bikes 587 .Where(b => b.Wheels > 3) // Filters - chainable (returns IQueryable of previous type) 588 .Where(b => b.IsBroken && b.HasTassles) 589 .Select(b => b.ToString()); // Map - we only this selects, so result is a IQueryable<string> 590 591 var sum = bikes.Sum(b => b.Wheels); // Reduce - sums all the wheels in the collection 592 593 // Create a list of IMPLICIT objects based on some parameters of the bike 594 var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles }); 595 // Hard to show here, but you get type ahead completion since the compiler can implicitly work 596 // out the types above! 597 foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome)) 598 Console.WriteLine(bikeSummary.Name); 599 600 // ASPARALLEL 601 // And this is where things get wicked - combine linq and parallel operations 602 var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name); 603 // this will happen in parallel! Threads will automagically be spun up and the 604 // results divvied amongst them! Amazing for large datasets when you have lots of 605 // cores 606 607 // LINQ - maps a store to IQueryable<T> objects, with delayed execution 608 // e.g. LinqToSql - maps to a database, LinqToXml maps to an xml document 609 var db = new BikeRepository(); 610 611 // execution is delayed, which is great when querying a database 612 var filter = db.Bikes.Where(b => b.HasTassles); // no query run 613 if (42 > 6) // You can keep adding filters, even conditionally - great for "advanced search" functionality 614 filter = filter.Where(b => b.IsBroken); // no query run 615 616 var query = filter 617 .OrderBy(b => b.Wheels) 618 .ThenBy(b => b.Name) 619 .Select(b => b.Name); // still no query run 620 621 // Now the query runs, but opens a reader, so only populates as you iterate through 622 foreach (string bike in query) 623 Console.WriteLine(result); 624 625 626 627 } 628 629 } // End LearnCSharp class 630 631 // You can include other classes in a .cs file 632 633 public static class Extensions 634 { 635 // EXTENSION METHODS 636 public static void Print(this object obj) 637 { 638 Console.WriteLine(obj.ToString()); 639 } 640 } 641 642 643 // DELEGATES AND EVENTS 644 public class DelegateTest 645 { 646 public static int count = 0; 647 public static int Increment() 648 { 649 // increment count then return it 650 return ++count; 651 } 652 653 // A delegate is a reference to a method. 654 // To reference the Increment method, 655 // first declare a delegate with the same signature, 656 // i.e. takes no arguments and returns an int 657 public delegate int IncrementDelegate(); 658 659 // An event can also be used to trigger delegates 660 // Create an event with the delegate type 661 public static event IncrementDelegate MyEvent; 662 663 static void Main(string[] args) 664 { 665 // Refer to the Increment method by instantiating the delegate 666 // and passing the method itself in as an argument 667 IncrementDelegate inc = new IncrementDelegate(Increment); 668 Console.WriteLine(inc()); // => 1 669 670 // Delegates can be composed with the + operator 671 IncrementDelegate composedInc = inc; 672 composedInc += inc; 673 composedInc += inc; 674 675 // composedInc will run Increment 3 times 676 Console.WriteLine(composedInc()); // => 4 677 678 679 // Subscribe to the event with the delegate 680 MyEvent += new IncrementDelegate(Increment); 681 MyEvent += new IncrementDelegate(Increment); 682 683 // Trigger the event 684 // ie. run all delegates subscribed to this event 685 Console.WriteLine(MyEvent()); // => 6 686 } 687 } 688 689 690 // Class Declaration Syntax: 691 // <public/private/protected/internal> class <class name>{ 692 // //data fields, constructors, functions all inside. 693 // //functions are called as methods in Java. 694 // } 695 696 public class Bicycle 697 { 698 // Bicycle's Fields/Variables 699 public int Cadence // Public: Can be accessed from anywhere 700 { 701 get // get - define a method to retrieve the property 702 { 703 return _cadence; 704 } 705 set // set - define a method to set a property 706 { 707 _cadence = value; // Value is the value passed in to the setter 708 } 709 } 710 private int _cadence; 711 712 protected virtual int Gear // Protected: Accessible from the class and subclasses 713 { 714 get; // creates an auto property so you don't need a member field 715 set; 716 } 717 718 internal int Wheels // Internal: Accessible from within the assembly 719 { 720 get; 721 private set; // You can set modifiers on the get/set methods 722 } 723 724 int _speed; // Everything is private by default: Only accessible from within this class. 725 // can also use keyword private 726 public string Name { get; set; } 727 728 // Properties also have a special syntax for when you want a readonly property 729 // that simply returns the result of an expression 730 public string LongName => Name + " " + _speed + " speed"; 731 732 // Enum is a value type that consists of a set of named constants 733 // It is really just mapping a name to a value (an int, unless specified otherwise). 734 // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong. 735 // An enum can't contain the same value twice. 736 public enum BikeBrand 737 { 738 AIST, 739 BMC, 740 Electra = 42, //you can explicitly set a value to a name 741 Gitane // 43 742 } 743 // We defined this type inside a Bicycle class, so it is a nested type 744 // Code outside of this class should reference this type as Bicycle.BikeBrand 745 746 public BikeBrand Brand; // After declaring an enum type, we can declare the field of this type 747 748 // Decorate an enum with the FlagsAttribute to indicate that multiple values can be switched on 749 // Any class derived from Attribute can be used to decorate types, methods, parameters etc 750 // Bitwise operators & and | can be used to perform and/or operations 751 752 [Flags] 753 public enum BikeAccessories 754 { 755 None = 0, 756 Bell = 1, 757 MudGuards = 2, // need to set the values manually! 758 Racks = 4, 759 Lights = 8, 760 FullPackage = Bell | MudGuards | Racks | Lights 761 } 762 763 // Usage: aBike.Accessories.HasFlag(Bicycle.BikeAccessories.Bell) 764 // Before .NET 4: (aBike.Accessories & Bicycle.BikeAccessories.Bell) == Bicycle.BikeAccessories.Bell 765 public BikeAccessories Accessories { get; set; } 766 767 // Static members belong to the type itself rather than specific object. 768 // You can access them without a reference to any object: 769 // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated); 770 public static int BicyclesCreated { get; set; } 771 772 // readonly values are set at run time 773 // they can only be assigned upon declaration or in a constructor 774 readonly bool _hasCardsInSpokes = false; // read-only private 775 776 // Constructors are a way of creating classes 777 // This is a default constructor 778 public Bicycle() 779 { 780 this.Gear = 1; // you can access members of the object with the keyword this 781 Cadence = 50; // but you don't always need it 782 _speed = 5; 783 Name = "Bontrager"; 784 Brand = BikeBrand.AIST; 785 BicyclesCreated++; 786 } 787 788 // This is a specified constructor (it contains arguments) 789 public Bicycle(int startCadence, int startSpeed, int startGear, 790 string name, bool hasCardsInSpokes, BikeBrand brand) 791 : base() // calls base first 792 { 793 Gear = startGear; 794 Cadence = startCadence; 795 _speed = startSpeed; 796 Name = name; 797 _hasCardsInSpokes = hasCardsInSpokes; 798 Brand = brand; 799 } 800 801 // Constructors can be chained 802 public Bicycle(int startCadence, int startSpeed, BikeBrand brand) : 803 this(startCadence, startSpeed, 0, "big wheels", true, brand) 804 { 805 } 806 807 // Function Syntax: 808 // <public/private/protected> <return type> <function name>(<args>) 809 810 // classes can implement getters and setters for their fields 811 // or they can implement properties (this is the preferred way in C#) 812 813 // Method parameters can have default values. 814 // In this case, methods can be called with these parameters omitted 815 public void SpeedUp(int increment = 1) 816 { 817 _speed += increment; 818 } 819 820 public void SlowDown(int decrement = 1) 821 { 822 _speed -= decrement; 823 } 824 825 // properties get/set values 826 // when only data needs to be accessed, consider using properties. 827 // properties may have either get or set, or both 828 private bool _hasTassles; // private variable 829 public bool HasTassles // public accessor 830 { 831 get { return _hasTassles; } 832 set { _hasTassles = value; } 833 } 834 835 // You can also define an automatic property in one line 836 // this syntax will create a backing field automatically. 837 // You can set an access modifier on either the getter or the setter (or both) 838 // to restrict its access: 839 public bool IsBroken { get; private set; } 840 841 // Properties can be auto-implemented 842 public int FrameSize 843 { 844 get; 845 // you are able to specify access modifiers for either get or set 846 // this means only Bicycle class can call set on Framesize 847 private set; 848 } 849 850 // It's also possible to define custom Indexers on objects. 851 // Although this is not entirely useful in this example, you 852 // could do bicycle[0] which returns "chris" to get the first passenger or 853 // bicycle[1] = "lisa" to set the passenger. (of this apparent quattrocycle) 854 private string[] passengers = { "chris", "phil", "darren", "regina" }; 855 856 public string this[int i] 857 { 858 get { 859 return passengers[i]; 860 } 861 862 set { 863 passengers[i] = value; 864 } 865 } 866 867 // Method to display the attribute values of this Object. 868 public virtual string Info() 869 { 870 return "Gear: " + Gear + 871 " Cadence: " + Cadence + 872 " Speed: " + _speed + 873 " Name: " + Name + 874 " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") + 875 "\n------------------------------\n" 876 ; 877 } 878 879 // Methods can also be static. It can be useful for helper methods 880 public static bool DidWeCreateEnoughBicycles() 881 { 882 // Within a static method, we only can reference static class members 883 return BicyclesCreated > 9000; 884 } // If your class only needs static members, consider marking the class itself as static. 885 886 887 } // end class Bicycle 888 889 // PennyFarthing is a subclass of Bicycle 890 class PennyFarthing : Bicycle 891 { 892 // (Penny Farthings are those bicycles with the big front wheel. 893 // They have no gears.) 894 895 // calling parent constructor 896 public PennyFarthing(int startCadence, int startSpeed) : 897 base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra) 898 { 899 } 900 901 protected override int Gear 902 { 903 get 904 { 905 return 0; 906 } 907 set 908 { 909 throw new InvalidOperationException("You can't change gears on a PennyFarthing"); 910 } 911 } 912 913 public static PennyFarthing CreateWithGears(int gears) 914 { 915 var penny = new PennyFarthing(1, 1); 916 penny.Gear = gears; // Oops, can't do this! 917 return penny; 918 } 919 920 public override string Info() 921 { 922 string result = "PennyFarthing bicycle "; 923 result += base.ToString(); // Calling the base version of the method 924 return result; 925 } 926 } 927 928 // Interfaces only contain signatures of the members, without the implementation. 929 interface IJumpable 930 { 931 void Jump(int meters); // all interface members are implicitly public 932 } 933 934 interface IBreakable 935 { 936 bool Broken { get; } // interfaces can contain properties as well as methods & events 937 } 938 939 // Classes can inherit only one other class, but can implement any amount of interfaces, 940 // however the base class name must be the first in the list and all interfaces follow 941 class MountainBike : Bicycle, IJumpable, IBreakable 942 { 943 int damage = 0; 944 945 public void Jump(int meters) 946 { 947 damage += meters; 948 } 949 950 public bool Broken 951 { 952 get 953 { 954 return damage > 100; 955 } 956 } 957 } 958 959 /// <summary> 960 /// Used to connect to DB for LinqToSql example. 961 /// EntityFramework Code First is awesome (similar to Ruby's ActiveRecord, but bidirectional) 962 /// https://docs.microsoft.com/ef/ef6/modeling/code-first/workflows/new-database 963 /// </summary> 964 public class BikeRepository : DbContext 965 { 966 public BikeRepository() 967 : base() 968 { 969 } 970 971 public DbSet<Bicycle> Bikes { get; set; } 972 } 973 974 // Classes can be split across multiple .cs files 975 // A1.cs 976 public partial class A 977 { 978 public static void A1() 979 { 980 Console.WriteLine("Method A1 in class A"); 981 } 982 } 983 984 // A2.cs 985 public partial class A 986 { 987 public static void A2() 988 { 989 Console.WriteLine("Method A2 in class A"); 990 } 991 } 992 993 // Program using the partial class "A" 994 public class Program 995 { 996 static void Main() 997 { 998 A.A1(); 999 A.A2(); 1000 } 1001 } 1002 1003 // String interpolation by prefixing the string with $ 1004 // and wrapping the expression you want to interpolate with { braces } 1005 // You can also combine both interpolated and verbatim strings with $@ 1006 public class Rectangle 1007 { 1008 public int Length { get; set; } 1009 public int Width { get; set; } 1010 } 1011 1012 class Program 1013 { 1014 static void Main(string[] args) 1015 { 1016 Rectangle rect = new Rectangle { Length = 5, Width = 3 }; 1017 Console.WriteLine($"The length is {rect.Length} and the width is {rect.Width}"); 1018 1019 string username = "User"; 1020 Console.WriteLine($@"C:\Users\{username}\Desktop"); 1021 } 1022 } 1023 1024 // New C# 6 features 1025 class GlassBall : IJumpable, IBreakable 1026 { 1027 // Autoproperty initializers 1028 public int Damage { get; private set; } = 0; 1029 1030 // Autoproperty initializers on getter-only properties 1031 public string Name { get; } = "Glass ball"; 1032 1033 // Getter-only autoproperty that is initialized in constructor 1034 public string GenieName { get; } 1035 1036 public GlassBall(string genieName = null) 1037 { 1038 GenieName = genieName; 1039 } 1040 1041 public void Jump(int meters) 1042 { 1043 if (meters < 0) 1044 // New nameof() expression; compiler will check that the identifier exists 1045 // nameof(x) == "x" 1046 // Prevents e.g. parameter names changing but not updated in error messages 1047 throw new ArgumentException("Cannot jump negative amount!", nameof(meters)); 1048 1049 Damage += meters; 1050 } 1051 1052 // Expression-bodied properties ... 1053 public bool Broken 1054 => Damage > 100; 1055 1056 // ... and methods 1057 public override string ToString() 1058 // Interpolated string 1059 => $"{Name}. Damage taken: {Damage}"; 1060 1061 public string SummonGenie() 1062 // Null-conditional operators 1063 // x?.y will return null immediately if x is null; y is not evaluated 1064 => GenieName?.ToUpper(); 1065 } 1066 1067 static class MagicService 1068 { 1069 private static bool LogException(Exception ex) 1070 { 1071 // log exception somewhere 1072 return false; 1073 } 1074 1075 public static bool CastSpell(string spell) 1076 { 1077 try 1078 { 1079 // Pretend we call API here 1080 throw new MagicServiceException("Spell failed", 42); 1081 1082 // Spell succeeded 1083 return true; 1084 } 1085 // Only catch if Code is 42 i.e. spell failed 1086 catch(MagicServiceException ex) when (ex.Code == 42) 1087 { 1088 // Spell failed 1089 return false; 1090 } 1091 // Other exceptions, or MagicServiceException where Code is not 42 1092 catch(Exception ex) when (LogException(ex)) 1093 { 1094 // Execution never reaches this block 1095 // The stack is not unwound 1096 } 1097 return false; 1098 // Note that catching a MagicServiceException and rethrowing if Code 1099 // is not 42 or 117 is different, as then the final catch-all block 1100 // will not catch the rethrown exception 1101 } 1102 } 1103 1104 public class MagicServiceException : Exception 1105 { 1106 public int Code { get; } 1107 1108 public MagicServiceException(string message, int code) : base(message) 1109 { 1110 Code = code; 1111 } 1112 } 1113 1114 public static class PragmaWarning { 1115 // Obsolete attribute 1116 [Obsolete("Use NewMethod instead", false)] 1117 public static void ObsoleteMethod() 1118 { 1119 // obsolete code 1120 } 1121 1122 public static void NewMethod() 1123 { 1124 // new code 1125 } 1126 1127 public static void Main() 1128 { 1129 ObsoleteMethod(); // CS0618: 'ObsoleteMethod is obsolete: Use NewMethod instead' 1130#pragma warning disable CS0618 1131 ObsoleteMethod(); // no warning 1132#pragma warning restore CS0618 1133 ObsoleteMethod(); // CS0618: 'ObsoleteMethod is obsolete: Use NewMethod instead' 1134 } 1135 } 1136} // End Namespace 1137 1138using System; 1139// C# 6, static using 1140using static System.Math; 1141 1142namespace Learning.More.CSharp 1143{ 1144 class StaticUsing 1145 { 1146 static void Main() 1147 { 1148 // Without a static using statement.. 1149 Console.WriteLine("The square root of 4 is {}.", Math.Sqrt(4)); 1150 // With one 1151 Console.WriteLine("The square root of 4 is {}.", Sqrt(4)); 1152 } 1153 } 1154} 1155 1156// New C# 7 Feature 1157// Install Microsoft.Net.Compilers Latest from Nuget 1158// Install System.ValueTuple Latest from Nuget 1159using System; 1160namespace Csharp7 1161{ 1162 // TUPLES, DECONSTRUCTION AND DISCARDS 1163 class TuplesTest 1164 { 1165 public (string, string) GetName() 1166 { 1167 // Fields in tuples are by default named Item1, Item2... 1168 var names1 = ("Peter", "Parker"); 1169 Console.WriteLine(names1.Item2); // => Parker 1170 1171 // Fields can instead be explicitly named 1172 // Type 1 Declaration 1173 (string FirstName, string LastName) names2 = ("Peter", "Parker"); 1174 1175 // Type 2 Declaration 1176 var names3 = (First:"Peter", Last:"Parker"); 1177 1178 Console.WriteLine(names2.FirstName); // => Peter 1179 Console.WriteLine(names3.Last); // => Parker 1180 1181 return names3; 1182 } 1183 1184 public string GetLastName() { 1185 var fullName = GetName(); 1186 1187 // Tuples can be deconstructed 1188 (string firstName, string lastName) = fullName; 1189 1190 // Fields in a deconstructed tuple can be discarded by using _ 1191 var (_, last) = fullName; 1192 return last; 1193 } 1194 1195 // Any type can be deconstructed in the same way by 1196 // specifying a Deconstruct method 1197 public int randomNumber = 4; 1198 public int anotherRandomNumber = 10; 1199 1200 public void Deconstruct(out int randomNumber, out int anotherRandomNumber) 1201 { 1202 randomNumber = this.randomNumber; 1203 anotherRandomNumber = this.anotherRandomNumber; 1204 } 1205 1206 static void Main(string[] args) 1207 { 1208 var tt = new TuplesTest(); 1209 (int num1, int num2) = tt; 1210 Console.WriteLine($"num1: {num1}, num2: {num2}"); // => num1: 4, num2: 10 1211 1212 Console.WriteLine(tt.GetLastName()); 1213 } 1214 } 1215 1216 // PATTERN MATCHING 1217 class PatternMatchingTest 1218 { 1219 public static (string, int)? CreateLogMessage(object data) 1220 { 1221 switch(data) 1222 { 1223 // Additional filtering using when 1224 case System.Net.Http.HttpRequestException h when h.Message.Contains("404"): 1225 return (h.Message, 404); 1226 case System.Net.Http.HttpRequestException h when h.Message.Contains("400"): 1227 return (h.Message, 400); 1228 case Exception e: 1229 return (e.Message, 500); 1230 case string s: 1231 return (s, s.Contains("Error") ? 500 : 200); 1232 case null: 1233 return null; 1234 default: 1235 return (data.ToString(), 500); 1236 } 1237 } 1238 } 1239 1240 // REFERENCE LOCALS 1241 // Allow you to return a reference to an object instead of just its value 1242 class RefLocalsTest 1243 { 1244 // note ref in return 1245 public static ref string FindItem(string[] arr, string el) 1246 { 1247 for(int i=0; i<arr.Length; i++) 1248 { 1249 if(arr[i] == el) { 1250 // return the reference 1251 return ref arr[i]; 1252 } 1253 } 1254 throw new Exception("Item not found"); 1255 } 1256 1257 public static void SomeMethod() 1258 { 1259 string[] arr = {"this", "is", "an", "array"}; 1260 1261 // note refs everywhere 1262 ref string item = ref FindItem(arr, "array"); 1263 item = "apple"; 1264 Console.WriteLine(arr[3]); // => apple 1265 } 1266 } 1267 1268 // LOCAL FUNCTIONS 1269 class LocalFunctionTest 1270 { 1271 private static int _id = 0; 1272 public int id; 1273 public LocalFunctionTest() 1274 { 1275 id = generateId(); 1276 1277 // This local function can only be accessed in this scope 1278 int generateId() 1279 { 1280 return _id++; 1281 } 1282 } 1283 1284 public static void AnotherMethod() 1285 { 1286 var lf1 = new LocalFunctionTest(); 1287 var lf2 = new LocalFunctionTest(); 1288 Console.WriteLine($"{lf1.id}, {lf2.id}"); // => 0, 1 1289 1290 int id = generateId(); 1291 // error CS0103: The name 'generateId' does not exist in the current context 1292 } 1293 } 1294}

Topics Not Covered

✨ New, 👍 Old, 🎈 LTS, 🔥 Cross-platform, 🎁 Windows-only

  • Attributes

  • Asynchronous Programming

  • Web Development

    • ASP.NET Core ✨
  • Desktop Development

    • Windows Presentation Foundation 👍 🎈 🎁
    • Universal Windows Platform ✨ 🎁
    • Uno Platform 🔥 ✨
    • WinForms 👍 🎈 🎁
    • Avalonia 🔥 ✨
    • WinUI ✨ 🎁
  • Cross-platform Development

    • Xamarin.Forms 👍
    • MAUI ✨

Further Reading