Lecture
C# (C Sharp) is a high-level object-oriented programming language from Microsoft, designed for the .NET platform. It was developed in 1998—2001 by a team of Microsoft engineers led by Anders Hejlsberg and Scott Wiltamuth[
It is used for:
Features of the C# language:
Unlike:
Comparison with other languages: JavaScript, C++, C, PHP

using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
}
}
3.1 A variable is a named area of memory that stores a value of a particular type.
int a = 10; // integer double b = 3.14; // fractional number bool isTrue = true; // boolean type string text = "Hi"; // string
var x = 5; // the compiler determines the type itself (int)
3.2 In C# there are two main kinds of storage (Stack vs Heap):
int, double, struct)int a = 5; // stored on the stack
class)var obj = new MyClass(); // object on the heap
int a = 5; int b = a; // copy MyClass o1 = new MyClass(); MyClass o2 = o1; // reference
void Foo(int x) { x = 100; }
Changes do not affect the original
ref, out, invoid Update(ref int x) { x = 50; } int a = 10; Update(ref a); // a = 50
Requirements:
void GetValue(out int x) { x = 42; } int result; GetValue(out result);
Features:
void Print(in int x) { Console.WriteLine(x); }
| Modifier | Read | Write | Requires initialization |
|---|---|---|---|
| value | yes | yes | yes |
| ref | yes | yes | yes |
| out | no | yes | no |
| in | yes | no | yes |
struct Point { public int X; }
class User { public string Name; }
In .NET there is an automatic garbage collector.
var obj = new MyClass(); obj = null; // the object is no longer used
The GC will remove it from memory later (not immediately). Memory is not freed when the method exits, nor with obj = null, immediately after the reference is removed
but rather
| Generation | What it stores |
|---|---|
| Gen 0 | new objects |
| Gen 1 | survived 1 collection |
| Gen 2 | long-lived |
When Gen 0 is full - a fast GC
When Gen 2 - a heavy full collection
— Working with Memory Without Allocations
— is a modern tool for working with memory without copying.
numbers = stackalloc int[3] {1, 2, 3};
Features:
Limitations:
ReadOnlySpan
ReadOnlySpan<char> text = "Hello";
Span<int> data = stackalloc int[10];
_ is a discard. It means:
"Evaluate the expression on the right, but I don't need the result."
public void OnButtonClick() { _ = ShareInternal(); } private async Task ShareInternal() { try { await Share(); } catch (Exception ex) { Debug.LogException(ex); } }
That is,
_ = ShareInternal();
does not mean
Task _ = ShareInternal();
The compiler treats this specifically as a discard.
But many code analyzers and the compiler may issue a warning:
CS4014: Because this call is not awaited, execution of the current method continues before the call is completed...
That is, they remind you:
"You called a method that returns a
Task, but you don'tawaitit. Is that definitely not a mistake?"
Does it have a type? No. A discard has no type or value of its own.
Only the expression on the right has a type:
ShareInternal(); // Task
but the discard itself stores nothing.
Does it have a value? No.
You cannot do this:
Console.WriteLine(_); // Error
or
var x = _;
Because a discard cannot be read.
Then why is _ sometimes an ordinary variable?
Because _ is not a reserved word in C#.
You can write:
int _ = 5;
Console.WriteLine(_); // 5
Here _ is an ordinary variable.
The compiler works it out from context:
_ = ShareInternal();
if there is no variable _ → this is a discard.
But if a variable _ already exists:
Task _;
_ = ShareInternal();
then this is already an assignment to a variable, not a discard.
That is why declaring variables named _ is generally not recommended, so as not to create confusion.
This is exactly why the statement
_ = ShareInternal();
has become the generally accepted way to show: "I am starting a Task and deliberately ignoring its result."
| Situation | Use |
|---|---|
| Small data | value type |
| Large objects | class |
| Need to modify an argument | ref |
| Need to return several values | out |
| Read-only without a copy | in |
| High performance | Span |
Copying large structs
Incorrect use of ref/out
Memory leaks through references
Trying to store a Span in a class field
Variables in C# are not just "containers" but a mechanism for managing memory:

In C#, data types can be divided into several groups.
byte //unsigned 8-bit type Range:0…255short // signed 16-bit type Range: -32,768 … 32,767 int // int — signed 32-bit type Range: -2,147,483,648 … 2,147,483,647 long // signed 64-bit type Range: -9,223,372,036,854,775,808 …9,223,372,036,854,775,807
Example:
int age = 25; long population = 8000000000;
float // less precise double // the standard fractional type decimal // precise, often used for money
Example:
double price = 10.5; float price = 10.5f; decimal money = 99.99m;
The m is required for decimal:
decimal salary = 1200.50m;
bool isActive = true; bool isDeleted = false;
char letter = 'A'; string name = "Ivan";
Important:
char // one character, single quotes string // text, double quotes
DateTime now = DateTime.Now; DateTime birthday = new DateTime(2000, 5, 10);
int[] numbers = { 1, 2, 3 }; string[] names = { "Ivan", "Olga" };
List<string> users = new List<string>(); Dictionary<string, int> ages = new Dictionary<string, int>();
class User { public string Name { get; set; } public int Age { get; set; } } User user = new User();
An ordinary int cannot be null:
int age = null; // error
But you can do this:
int? age = null; DateTime? deletedAt = null;
object can store a value of any type:
object value = 123; object text = "Hello";
But it is better to use specific types rather than object.
int[] numbers = {1, 2, 3, 4};
Console.WriteLine(numbers ); // 1
Iteration:
foreach (var n in numbers)
{
Console.WriteLine(n);
}
Delegates — yes, they are a separate type.
In C#, a delegate is a reference type that stores a reference to a method.
public delegate void MyHandler(string message);
Example:
void Print(string text) { Console.WriteLine(text); } MyHandler handler = Print; handler("Hello");
Events are not a separate data type.
event is a special class member that is based on a delegate.
public event MyHandler SomethingHappened;
That is:
event = subscription mechanism for delegate
In short:
| Construct | Is it a type? | What it is |
|---|---|---|
delegate |
yes | a reference type for storing a method |
event |
no | a class member, a wrapper around a delegate |
Action |
yes | a ready-made delegate with no return value |
Func |
yes | a ready-made delegate with a return value |
Example of the modern variant:
public event Action<string> MessageReceived;
Here Action is a delegate, and MessageReceived is an event.
Tuple and ValueTuple) In C#, tuples (Tuple and the more modern ValueTuple) let you store several values of different types in a single structure. A simple usage example:
using System;
class Program
{
static void Main()
{
// Creating a tuple with two elements
(string Name, int Age) person = ("Ivan", 30);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
// A tuple with three elements
var point = (X: 10, Y: 20, Z: 30);
Console.WriteLine($"Point: ({point.X}, {point.Y}, {point.Z})");
// Returning a tuple from a method
var result = GetMinMax(new int[] { 5, 2, 9, 1 });
Console.WriteLine($"Min: {result.min}, Max: {result.max}");
}
static (int min, int max) GetMinMax(int[] numbers)
{
int min = int.MaxValue;
int max = int.MinValue;
foreach (var n in numbers)
{
if (n < min) min = n;
if (n > max) max = n;
}
return (min, max);
}
}
(string Name, int Age) declares named tuple elements.
You can use var for automatic type inference.
Tuples are convenient for returning several values from a method without creating a separate class.

A short table of data types in C#
| Type | Purpose |
|---|---|
int |
integers |
long |
large integers |
double |
floating-point numbers |
decimal |
money, exact calculations |
bool |
true / false |
char |
a single character |
string |
text |
DateTime |
date and time |
int[] |
an array of numbers |
List |
a list |
Dictionary |
key-value pairs |
object |
any type |
int? |
a nullable number |
| Category | Type | Is it a type? | Description |
|---|---|---|---|
| Value Types | int, double, bool, char |
+ | Store the value directly |
struct |
+ | User-defined value types | |
enum |
+ | A set of constants | |
Nullable (int?) |
+ | A value type that can hold null |
|
| Reference Types | class |
+ | The main OOP type |
string |
+ | A string (a special reference type) | |
array |
+ | An array | |
object |
+ | The base type for all types | |
interface |
+ | A contract | |
List, Dictionary<,> |
+ | Collections | |
| Delegates and events | delegate |
+ | A reference type (a pointer to a method) |
Action, Func |
+ | Ready-made delegates | |
event |
no | A wrapper around a delegate (not a type) |
Variables and classes of one type can be turned into entities of other types using casting, boxing and unboxing.
Casting in C# is simply the conversion of one type to another (explicit or implicit), whereas boxing and unboxing specifically involve moving between value types and reference types. Boxing wraps a value in an object on the heap, and unboxing extracts it back.
Main differences between type conversions
| Mechanism | What it does | Example | Notes |
|---|---|---|---|
| Casting |
Converts a value of one type to another (within compatible types). |
double d = 3.14; int i = (int)d; |
Can be explicit ((int)) or implicit (for example, int → double). Does not create an object on the heap. |
| Boxing |
Wraps a value type (for example, int) in an object (System.Object or an interface). |
int i = 5; object o = i; |
An implicit process. The CLR copies the value from the stack to the heap and returns a reference. |
| Unboxing |
Extracts the value from an object back into a value type. |
object o = 5; int i = (int)o; |
An explicit process. Requires the correct type, otherwise an InvalidCastException is thrown. |
Key points
int a = 5, b = 3; Console.WriteLine(a + b); // 8 Console.WriteLine(a - b); // 2 Console.WriteLine(a * b); // 15 Console.WriteLine(a / b); // 1 (integer division!)
if (a > b && b > 0)
{
Console.WriteLine("OK");
}
int x = 10;
if (x > 5)
{
Console.WriteLine("Greater than 5");
}
else
{
Console.WriteLine("Less than or equal to 5");
}
int day = 1;
switch (day)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
default:
Console.WriteLine("Another day");
break;
}
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
int i = 0;
while (i < 5)
{
Console.WriteLine(i);
i++;
}
Inside a foreach loop you usually cannot change the loop variable itself:
int[] numbers = { 1, 2, 3, 4, 5 }; foreach (int number in numbers) { Console.WriteLine(number); }
The same thing using var. var means that C# determines the variable's type on its own. In this case number will be int.
foreach (var number in numbers) { Console.WriteLine(number); }
An example of foreach with List
List<string> users = new List<string> { "Ivan", "Olga", "Maria" }; foreach (var user in users) { Console.WriteLine(user); }
An example of foreach with Dictionary in C#:
Dictionary<string, int> ages = new Dictionary<string, int> { { "Ivan", 25 }, { "Olga", 30 }, { "Maria", 22 } }; foreach (var item in ages) { Console.WriteLine(item.Key + " = " + item.Value); }
Output:
Ivan = 25 Olga = 30 Maria = 22
static int Sum(int a, int b)
{
return a + b;
}
Usage:
int result = Sum(2, 3);
class Person
{
public string Name;
public int Age;
public void SayHello()
{
Console.WriteLine("Hello, I am " + Name);
}
}
Usage:
Person p = new Person(); // creation, instantiation p.Name = "Ivan"; // assignment p.Age = 30; // assignment
Console.WriteLine("Hello, I am " + p.Name );// reading a value
p.SayHello();// calling a method
public class Person
{
// A private field is hidden from external code
private string _name;
// A public property with validation logic
public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("The name cannot be empty");
_name = value;
}
}
// The constructor sets the initial state
public Person(string name)
{
Name = name; // We use the property, not the field directly
}
// An additional method encapsulates behavior
public void Rename(string newName)
{
Name = newName;
}
}
class Animal
{
public void Speak()
{
Console.WriteLine("Sound");
}
}
class Dog : Animal
{
name = "Dog";
}
class Animal
{
public virtual void Speak()
{
Console.WriteLine("Sound");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof");
}
}
try
{
int x = int.Parse("abc");
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
In C#, memory management is usually handled by the Garbage Collector (GC). However, if your code uses system resources (files, database connections, network sockets), the GC may not release them promptly enough.
To solve this problem, there is the IDisposable interface with a single method, Dispose(). The using statement is "syntactic sugar" that guarantees this method will be called automatically.
Why is this needed?
Imagine you have opened a file for writing. If the program "crashes" because of an error before you close the file, it may remain locked by the operating system.
using creates a try-finally block in which the call to Dispose() happens in the finally section. This guarantees that the resource is released even if an exception occurs.
Ways to use it
This form clearly limits the variable's scope to the curly braces. As soon as execution leaves the braces, the resource is released.
using (var stream = new FileStream("test.txt", FileMode.Create))
{
// Work with the file
} // stream.Dispose() is called automatically here
A more modern and concise approach. You do not need curly braces: the resource will be released at the end of the current method or code block.
void WriteData()
{
using var stream = new FileStream("test.txt", FileMode.Create);
// Work with the file
// Dispose() will be called automatically when the method exits
}
How it works "under the hood"
The compiler expands the using construct into a try-finally construct.
An example of the compiler's logic:
{
var resource = new MyResource();
try
{
// Using the resource
}
finally
{
if (resource != null)
((IDisposable)resource).Dispose();
}
}
When should you use it?
The rule is simple: if a class implements IDisposable, you almost always need to wrap it in using.
Common examples:
Working with files: StreamReader, StreamWriter, FileStream.
Networking: HttpClient (although there are nuances with reusing it), TcpClient.
Databases: SqlConnection, DbContext in Entity Framework.
Graphics: Bitmap, Pen, Brush.
Generics in C# are a way to write universal code that works with different data types without losing type safety.
A simple definition
A generic is a type template in which a specific type is substituted later.
An example without generics (bad)
class Box
{
public object Value;
}
Problems:
Box box = new Box(); box.Value = 123; int x = (int)box.Value; // cast
With generics (correct)
Usage:
No casts, everything is strictly typed
Where generics are used
is a list that can store only int. Trying to add a string causes a compilation error.
is a dictionary in which the keys are strictly string and the values are strictly int. This guarantees type safety.
List
Usage:
int x = GetFirst(new int[] {1, 2, 3});
string s = GetFirst(new string[] {"a", "b"});
You can specify which types are allowed:
Examples:
where T : class // reference types only where T : struct // value types only where T : new() // must have a constructor
The strength of generics
| Without generics | With generics |
|---|---|
| object | a specific type |
| casts | no casts |
| runtime errors | errors at compile time |
| slower | faster |
The key idea
Generics = a type is passed as a parameter
Here T means "any type"
Summary
Comparison with Java generics
Generics in the CLR are implemented not as "compiler sugar" but as a fundamental part of the virtual machine itself: they exist at the level of IL and metadata, and the JIT compiler performs real specialized expansion for value types and code sharing for reference types. This makes generics in .NET much more powerful and efficient than, for example, in Java, where they are implemented through type erasure.
| Characteristic | CLR (.NET) generics | Java generics |
|---|---|---|
| Implementation | Built into IL and the CLR | Type erasure |
| Performance | Almost like hand-written code | Sometimes requires boxing |
| Reflection | Full type information | Limited (the type is erased) |
| Value types | Specialization without boxing | Not supported (objects only) |
| Code sharing | For reference types | None (every generic is erased to Object) |
An extension method in C# is a static method that lets you "add" new methods to an existing type (class, struct, interface) without changing its source code and without creating a derived class. Such methods look like ordinary instance methods, but they are implemented in a separate static class.
Main characteristics
using System;
public static class StringExtensions
{
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
class Program
{
static void Main()
{
string sentence = "C# extension methods are powerful";
Console.WriteLine("Word Count: " + sentence.WordCount());
}
}
Result: Word Count: 5 The WordCount() method looks like a built-in string method.
class Student
{
public string Name { get; set; }
public int Marks { get; set; }
}
public static class StudentExtensions
{
public static void PrintResult(this Student s)
{
Console.WriteLine(s.Marks >= 40
? $"{s.Name} Passed"
: $"{s.Name} Failed");
}
}
class Program
{
static void Main()
{
var s1 = new Student { Name = "Alex", Marks = 75 };
var s2 = new Student { Name = "Maria", Marks = 35 };
s1.PrintResult(); // Alex Passed
s2.PrintResult(); // Maria Failed
}
}
public interface ILogger
{
void Log(string message);
}
public static class LoggerExtensions
{
public static void LogError(this ILogger logger, string error)
{
logger.Log("ERROR: " + error);
}
}
Now any class that implements ILogger automatically gets the LogError() method.
C# runs on the .NET platform, which:
C# is:
1. Which data type is used to store integers in C#?
Hint: C# has different numeric types: integer types (without a fractional part) and floating-point types. They differ in size and range of values. Think about the basic numeric types: there are separate ones for whole and for fractional values. You need the one without a fractional part.
2. What denotes the entry point of a program?
Hint:Every console application in C# must have a method that serves as the start of execution. It has a fixed name and signature. This is a special method where program execution begins. It is always called first.
3. Which data type is used to store text?
Hint: Text in C# is a sequence of characters. A separate reference data type is used for it. Think: a single character is one type, and a string of characters is another.
4. How do you declare a variable with automatic type inference?
Hint: C# supports type inference, in which the compiler determines the variable's type by itself at compile time. There is a keyword that lets the compiler determine the type from the value.
5. Which operator is used to compare variables?
Hint:Programming languages have separate operators for assigning a value and for comparing values. Do not confuse it with the assignment operator: these are two different operations.
6. How do you declare an array in C#?
Hint: An array is a data structure that contains elements of the same type arranged sequentially in memory. In C#, you first specify the element type, and then indicate that it is a fixed-size collection.
7. Which loop is used to iterate over a collection?
Hint:C# has several kinds of loops, but one of them is optimized specifically for iterating over the elements of collections. There is a loop designed specifically for working with collections, without indexes.
8. What does the class keyword mean?
Hint: A class is a template (a description) from which objects are created. It can contain fields, methods and properties. It is the foundation of object-oriented programming.
9. Which data type takes the values true or false?
Hint:C# has a special type for storing logical values: true or false. This is the logical type used in conditions.
10. How do you declare a method with no return value?
Hint:Methods in C# can return a value or return nothing. A separate keyword is used for the second case.
11. Which type is used to store fractional numbers?
Hint: Numbers with a fractional part use floating-point types, which let you store values with precision.
12. Which data type is a reference type?
Hint: C# has two main kinds of types: value types and reference types. Think: does the variable store the value itself or a reference to an object?
13. Which operator is used for logical AND?
Hint:Logical operators are used to combine conditions. They work with Boolean values. The operator must return true only if both conditions are true.
14. How do you create an object of a class, and what is this process called (instantiation)?
Hint:An object is created from a class using an operator that allocates memory and calls the constructor. A special keyword is used to create an instance.
15. What is a delegate?
Hint: Delegates are types that can store references to methods and call them. This is related to passing methods as parameters.
16. What is an event in C#?
Hint:Events in C# are built on delegates and make it possible to implement the "observer" pattern. They are used to implement a mechanism of subscriptions and notifications.
17. What are generics in C#?
Hint:Generics let you create universal classes and methods that are not tied to a specific type. They let you write code that works with different types.
18. Which type is used for key-value pairs in C#?
Hint:C# has collections that implement associative arrays (key - value). A structure in which each key corresponds to a value.
19. What does the static keyword do in C#?
Hint: Static members belong to the class, not to a specific instance. It is related not to an object but to the class itself.
20. Which type can store any type of data?
Hint:C# has a universal type from which all other types inherit. It is the base type for all objects.
21. How do you declare a nullable type?
Hint:Nullable types allow value types to take the value null. There is a way to indicate that a value may be absent.
22. What does try-catch do?
Hint:The exception-handling construct lets you catch errors while the program is running. It is used when working with potentially dangerous code.
23. Which data type stores a single character?
Hint:C# has a separate type for storing a single Unicode character. Do not confuse it with a string, which can contain many characters.
24. Which type is used for date and time?
Hint:C# provides a special type for storing a date and time, with the ability to perform operations on them. It is the standard built-in type for working with dates.
25. Which method prints text to the console?
Hint: .NET has a class for console input/output that contains methods for displaying text. It belongs to the standard class for working with the console.
26. What does `where T : class` mean in a generic constraint?
Hint: In generics, you can constrain types. The class constraint means the parameter must support the behavior of reference types: passing by reference and the ability to be null. It is not a value, but a reference.
27. What does the `??` operator do?
Hint: This is the null-coalescing operator. It checks a value and substitutes a fallback if the value is missing (null).
"If the left side is empty, take the right."
28. Which modifier allows a method to be overridden in a derived class?
Hint: For a method to be changeable (overridable) in a descendant, it must be marked in the base class.
Clue: it is like "permission to change the behavior".
29. Which modifier is used when overriding a method?
Hint: In the derived class, a special keyword is used to replace the implementation of the base method.
Clue: "rewrite over the existing one".
30. What does `IEnumerable
Hint: This is an interface that lets you walk through a collection sequentially (for example, in a loop).
It works with foreach.
31. How does `IQueryable
Hint: One works with data that is already loaded, the other can build a query (for example, SQL) and execute it later.
"Lazy execution and a remote source."
32. What does `async` on a method mean?
Hint: It lets a method use asynchronous operations and write code as if it were synchronous.
It is needed to work with await.
If a function needs to wait for something to complete with await, the function must have async so that code execution as a whole is not blocked.
33. What does `Task
Hint: It represents an asynchronous operation. It can return a result or simply a completion signal.
A wrapper around a future result.
34. What does `await` do?
Hint: It suspends the method until the task completes, but does not block the thread.
"Wait, but don't freeze the thread."
35. What is boxing?
Hint: When a value (value type) is packed into an object (object or an interface).
A value turns into a reference.
36. What is unboxing?
Hint: The reverse process: extracting the value from the object. Getting the "pure value" back.
37. How does `struct` differ from `class`?
Hint: One is stored as a value (copied), the other as a reference. struct is a value type.
38. What does `readonly` mean for a field?
Hint: The field can be set only once, at declaration or in a constructor. It cannot be changed after creation.
39. What does `const` mean?
Hint: The value is fixed before the program even starts (at compile time). It never changes at all.
40. What does `yield return` do?
Hint: It lets you return elements one at a time, creating a lazy sequence. "Not everything at once, but in parts."
41. What is an extension method?
Hint: It lets you add a method to an existing type without changing its code. As if you had "added a method to someone else's class".
42. How must an extension method be declared?
Hint: There are strict rules: the method and the class must be special, and the first parameter indicates what is being extended. The this keyword in the parameter.
43. What does the LINQ method `Select` do?
Hint: It transforms each element into a new form. "map" in other languages.
44. What does the LINQ method `Where` do?
Hint: It selects elements by a condition. A filter.
45. What does `sealed class` mean?
Hint: It forbids inheriting from the class. "You can't go further." (the equivalent of final in other programming languages)
46. What are nullable reference types?
Hint: They let the compiler track where null is possible and warn about errors. Null control at compile time.
47. What does the `?.` operator do?
Hint: Safe access to an object: if it is null, there will be no error. "Check before accessing."
48. How does `abstract class` differ from `interface`?
Hint: One can store state and implementation, the other only a contract (in the classical sense). The presence of fields and code inside.
49. What does `using` do when working with `IDisposable`?
Hint: It automatically releases resources after the object is used. A call to Dispose() without your involvement.
50. What is a delegate in C#?
51. What happens with covariance in delegates?
52. What does contravariance mean?
53. What is an expression tree (`Expression
54. How does `Func
55. What does `Span
56. Why can't `Span
57. What does the `ref` keyword do when passing a parameter?
58. How does `ref` differ from `out`?
59. What is an `in` parameter?
60. What does `readonly struct` do?
61. What does `stackalloc` do?
62. What does `await using` mean?
63. What does `IAsyncEnumerable
64. What does `yield break` mean?
65. What does the `ConfigureAwait(false)` method do?
66. What is boxing cost?
67. What does `lock` do?
68. What is a deadlock?
69. What does `volatile` do?
70. What is the GC (Garbage Collector)?
71. What does `weak reference` mean?
72. What does `Activator.CreateInstance` do?
73. What is reflection?
74. What does `nameof()` do?
75. What is JIT compilation?
76. What does the statement _ = ShareInternal(); mean if ShareInternal() returns a Task?
Explanation: the _ = statement uses a discard and shows that the returned Task is deliberately ignored. The method is started, but the calling code does not wait for it (await is not performed), so this is a typical fire-and-forget pattern.
Comments