Current mission: finish filling in the OTDs
SNCA:C Sharp/Tutorial
This is a brief tutorial on the C# programming language.
This tutorial assumes modern C# (C# 10+ / .NET 6+).
Hello World[edit | edit source]
The Hello World program in C# is as follows:
using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello, world!");
}
}
using System; imports the base library that contains Console.
Main is the entry point of the program. Unlike C, it does not need to return an int, though it can (static int Main()).
You can also use command-line arguments:
static void Main(string[] args)
{
Console.WriteLine(args.Length);
}
Basic Types[edit | edit source]
C# has strongly-typed variables:
int: 32-bit integerlong: 64-bit integerfloat: 32-bit floating pointdouble: 64-bit floating pointdecimal: high-precision decimal (for money)char: single characterstring: text (immutable)bool: true or falseobject: base type of all types
Other deeply fundamental types include:
T?: a nullable type, representing either a value of typeTornull(no value)T[]: an array of objects of typeTof fixed lengthTuple<T1, T2, ..., T7, TRest>: a tuple type, which can hold multiple values of possibly different typesList<T>: a dynamic array storing objects of typeTDictionary<K, V>: a dictionary-like type storing keys of typeK, and mapping them to values of typeVIEnumerable<T>: a sequence of elements of typeTthat can be iterated over
Variables[edit | edit source]
Much like in other languages, variables in C# are declared with a type followed by a name.
Note that variables must be assigned before use (unlike C, you cannot safely use uninitialized variables). However, fields (class-level variables) automatically receive default values.
using System;
class Program
{
static void Main()
{
int age = 18;
string name = "Nate";
string website = "example.com";
Console.WriteLine($"{name} is {age}, and posts on {website}!");
}
}
Here:
int age = 18;declares a variable named age of type int assigned with value 18string name = "Nate";declares a string assigned with value Nate
The type of a variable can also be omitted by declaring the variable using var keyword. The compiler will automatically infer the type based on the assigned value. However, even though var is used, the variable is still strongly typed. Its type is determined at compile time and cannot change later.
There is also const which defines an compile-time constant for the variable. Compile time constraints must be known at compile time and cannot be changed afterwards.
const int example_const = 300;
In addition to const there is also readonly which is simluar to a runtime constraint but can be assigned at declaration or in a constructor and cannot be modified afterwards.
class Example
{
readonly int value = 10;
}
Operators[edit | edit source]
Comparison operators compare two values:
>: greater than<: less than>=: greater than or equal to<=: less than or equal to==: equal to!=: not equal to
Examples:
bool a = 5 > 3; // true bool b = 5 < 3; // false bool c = 5 == 5; // true bool d = 5 != 2; // true
Logical operators combine multiple boolean expressions:
&&: logical AND (both conditions must be true)
||: logical OR (at least one condition must be true)
!: logical NOT (inverts a boolean value)
Examples:
bool a = (5 > 3 && 10 > 2); // true (both are true) bool b = (5 > 10 || 2 > 1); // true (second condition is true) bool c = !(5 > 3); // false (inverts true)
Control Flow[edit | edit source]
If/else[edit | edit source]
if, else if, and else allow you to check boolean conditions and execute code based on them.
You can have any number of else if blocks (including zero). You can also have just an if block by itself. However, you cannot have an else or else if without a preceding if.
Each condition must evaluate to a bool (true or false). Unlike C, integers cannot be implicitly treated as booleans. You must explicitly compare values.
Example:
using System;
class Program
{
static void Main()
{
Console.Write("Enter a number: ");
int number = int.Parse(Console.ReadLine());
Console.WriteLine();
if (number > 0)
{
Console.WriteLine($"The number {number} is positive.");
}
else if (number < 0)
{
Console.WriteLine($"The number {number} is negative.");
}
else
{
Console.WriteLine("The number is exactly 0.");
}
}
}
Switch[edit | edit source]
A switch statement in C# selects a path based on the value of an expression. It is often cleaner than long chains of if/else, especially when comparing a single value against many possibilities.
A switch block consists of case labels and an optional default case which is executed if no case matches.
To prevent execution from continuing into the next case, you must explicitly end each case with break, return, or another jump statement. Unlike C, C# does not allow implicit fallthrough between cases.
Example:
using System;
class Program
{
static void Main()
{
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
default:
Console.WriteLine("Some other day");
break;
}
}
}
C# also provides a more concise form called a switch expression, which evaluates to a value:
int day = 3;
string result = day switch
{
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
_ => "Some other day"
};
Console.WriteLine(result);
Goto[edit | edit source]
Additionally, if you are a complete pajet and like slop codding, there is also goto. goto is generally considered bad practice because it can make code harder to read and maintain (“spaghetti code”). It is rarely needed
A goto statement allows you to jump directly to another labeled part of the code. To define a label, write label: at a location, then use goto label; to jump to it.
using System;
class Program
{
static void Main()
{
int i = 0;
start:
Console.WriteLine($"i = {i}");
i++;
if (i < 5)
{
goto start;
}
Console.WriteLine("Done");
}
}
One neat feature with goto is that you can also use goto case inside a switch to jump between cases.
Loops[edit | edit source]
A loop allows you to repeatedly execute a block of code.
Loops support the following keywords:
break: immediately exits the loopcontinue: skips the rest of the current iteration and continues with the next one
For loop[edit | edit source]
A for loop is used when you know exactly how many times you want to iterate.
Example:
using System;
class Program
{
static void Main()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"i = {i}");
}
}
}
While loop[edit | edit source]
A while loop repeats as long as its condition is true. It is typically used when the number of iterations is not known in advance.
Example:
using System;
class Program
{
static void Main()
{
int i = 0;
while (i < 5)
{
Console.WriteLine($"i = {i}");
i++;
}
}
}
Do-while loop[edit | edit source]
A do-while loop is similar to a while loop, except it always executes at least once before checking the condition.
Example:
using System;
class Program
{
static void Main()
{
int i = 0;
do
{
Console.WriteLine($"i = {i}");
i++;
} while (i < 5);
}
}
Generics[edit | edit source]
Generics allow you to write code that works with any type allowing for flexible, reusable code.
A generic type uses the syntax <T>, where T is a placeholder for a real type.
For example, a generic list:
List<int> numbers = new List<int>(); List<string> names = new List<string>();
Here, List<T> can store any type, depending on what is provided for T.
You can also create your own generic methods:
static T Identity<T>(T value) { return value; }
This method takes a value of any type T and returns it.
Generics can also have constraints to restrict what types are allowed:
static void Print<T>(T value) where T : class { Console.WriteLine(value); }
Here, where T : class means T must be a reference type.
Take for example this function singature which demonstrates several real world advanced concepts:
public async Task<StatusResponse<List<T>>> ReadWhereAsync<T>( Expression<Func<T, bool>> predicate) where T : class
<T>: allows the method to work with any typewhere T : class: restricts T to reference typesTask<...>+async/await: performs the operation asynchronouslyIQueryable<T>: builds a query that can be executed later (commonly used with databases)Func<...>: allows passing a function to modify the queryStatusResponse<...>: a custom wrapper type used to standardize success/error responses
LINQ[edit | edit source]
One of the languages coolest and powerful features is LINQ (Language Integrated Query). LINQ allows you to query and manipulate data from various sources in a concise way. LINQ is heavily used in C#, especially when working with collections, databases, and APIs. It operates on sequences such as IEnumerable<T>.
Example:
using System;
using System.Linq;
class Program {
static void Main()
{
int[] numbers = { 1, 2, 3, 4, 5 };
var evens = numbers.Where(x => x % 2 == 0);
foreach (var n in evens)
{
Console.WriteLine(n);
}
}
}
Here:
Wherefilters elements based on a conditionx => x % 2 == 0is a lambda expression that returns true for even numbers.
You can also chain multiple LINQ operations together to filter, transform, or sort data in a single expression.
For example using the earlier numbers dataset:
var result = numbers.Where(x => x > 2) .Select(x => x * 2) .ToList();
In this case:
Wherefilters values greater than 2Selecttransforms each element by multiplying it by 2ToListmaterializes the result into a list
LINQ also supports logical operators inside expressions, such as && (AND) and || (OR), when building conditions inside lambdas.
Common LINQ operations[edit | edit source]
Where: filters elements based on a conditionSelect: transforms each elementOrderBy: sorts elements in ascending orderOrderByDescending: sorts elements in descending orderAny: checks if any element matches a conditionAll: checks if all elements match a conditionFirst/FirstOrDefault: returns the first matching elementToList: converts a sequence into a listCount: returns the number of elements