In C# there is no import of file. Import of code is done using namespaces.
Import a namespace using:
using System;
using System.Collections.Generic;
using MyNamespace;
Create a namespace using:
MyNamespace {
// Code of my MyNamespace
}
You can use the same namespace in different files. Every code block inside the same namespace can access information from this namespace from other files:
In file1.cs:
MyNamespace {
class MyClassFile1{
// Code of my MyClassFile1
}
}
In file2.cs:
MyNamespace {
class MyClassFile2{
mcf1 = new MyClassFile1();
}
}
Print in console using:
Console.WriteLine("Hello World"); // Add breakline after text
Console.Write("Hello World"); // Does not add breakline after text
You can write variable values using {}
and using a $
at the beginning of the string:
int i = 1, j = 2;
Console.WriteLine($"{i.ToString()} is smaller than {j.ToString()}");
ToString()
is used to cast variable to string.
A Ternary Operator syntax is condition ? statement 1 : statement 2
.
It returns statement 1 if condition is true and statement 2 otherwise.
int x = 20, y = 10;
var result = x > y ? "x is greater than y" : "x is less than y";
Console.WriteLine(result); // x is greater than y
The switch
statement can be used instead of if else statement when you want to test a variable against three or more conditions.
int x = 10;
switch (x) {
case 5:
Console.WriteLine("Value of x is 5");
break;
case 10:
Console.WriteLine("Value of x is 10");
break;
case 15:
Console.WriteLine("Value of x is 15");
break;
default:
Console.WriteLine("Unknown value");
break;
}
// Value of x is 10
for(int i = 0; i < 10; i++) {
//code block
}
while (i < 10) {
//code block
i++;
}
The do while loop is the same as while loop except that it executes the code block at least once.
do {
//code block
i++;
} while (i < 5);
char[] charArray = {'H','e','l','l','o'};
foreach(char c in charArray) {
//code block
}
See also this Microsoft C# documentation page on exceptions handling.
A try
block is used by C# programmers to partition code that might be affected by an exception.
The catch
block deals with exceptional circumstances (errors).
The finally
block is used to release the resources regradless that an error occured or no.
using System.IO
void ReadFile(string path) {
try {
reader = new StreamReader(path);
string? line = reader.ReadLine();
while (line != null)
{
Console.WriteLine(line);
line = reader.ReadLine();
}
}
catch (Exception e) {
Console.WriteLine($"Error: {e.Message}");
}
finally {
// if reader could open the file but error occurs after
if (reader != null)
reader.Close();
}
}
Enum
is a simple data structure used to declare a set of named constants. Enum
is based on types byte or sbyte or short or ushort or int or uint or long or ulong or int.
An enum declaration that does not explicitly declare an underlying type has an underlying type of int.
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
Console.WriteLine(Color.Green); // Green
Console.WriteLine((int) Color.Green); // 1
enum Color: long {
Red = -1,
Green = 5,
Blue = 8
}
Assigned values does not require to be unique. This is valid:
enum Color: long {
Red = -1,
Green = 5,
Blue = 5
}
Mutable and immutable are English words that mean “can change” and “cannot change” respectively. The meaning of these words is the same in C# programming language; that means the mutable types are those whose data members can be changed after the instance is created but Immutable types are those whose data members can not be changed after the instance is created.
Both structs and classes can be either mutable or immutable. All four combinations are possible. If a struct or class has non-readonly public fields, public properties with setters, or methods which set private fields, it is mutable because you can change its state without creating a new instance of that type.
From this Toward Data Science blog post.
Multitasking is the simultaneous execution of multiple tasks or processes over a certain time interval. Multithreading and multiprocessing are two ways to achieve multitasking.
Multithreading refers to the ability of a processor to execute multiple threads concurrently, where each thread runs a process. Whereas multiprocessing refers to the ability of a system to run multiple processors concurrently, where each processor can run one or more threads.
Multithreading is a way to achieve multitasking by executing multiple threads concurrently on a processor, where each thread runs a process.
Example from Geeks for Geeks:
using System;
using System.Threading;
public class GFG
{
public static void method1() {
for (int = 0; i <= 5; i++) {
Console.WriteLine("Method1 is : {0}", i);
if (i == 3)
Thread.Sleep(6000); // 6s
}
}
public static void method2() {
for (int j = 0; j <= 5; j++)
Console.WriteLine("Method2 is : {0}", j);
}
static public void Main() {
Thread thr1 = new Thread(method1);
Thread thr2 = new Thread(method2);
thr1.Start();
thr2.Start();
}
}
The output will look like something like this (Method2 does not wait Method1 to finish for starting):
Method1 is : 0
Method1 is : 1
Method2 is : 0
Method1 is : 2
Method1 is : 3
Method2 is : 1
Method2 is : 2
Method2 is : 3
Method2 is : 4
Method2 is : 5
Method1 is : 4
Method1 is : 5
Parallel.For
syntax is Parallel.For(from, to, function)
. Parallel.For
will apply on multiple threads the function function
for every values between from and to (exclude).
It is equivalent to the classic
for (i=from; i < to; i++)
function(i);
Example from Dot Net Tutorials:
using System.Threading.Tasks;
Parallel.For(1, 11, number => {
Console.WriteLine(number); // 1 2 3 4 5 6 7 8 10 9
});
Parallel.For
syntax is Parallel.For(from, to, function)
. Parallel.For
will apply on multiple threads the function function
for every values between from and to (exclude).
Example from Dot Net Tutorials:
using System.Collections.Generic;
using System.Threading.Tasks;
List<int> integerList = Enumerable.Range(1, 10).ToList();
Parallel.ForEach(integerList, i =>
{
Console.WriteLine("{0}", i); // 3 7 4 8 5 1 6 9 2 10
});
C# does not really have Multiprocessing feature (from this StackOverflow post).
Boxing converts a Value Type variable into a Reference Type variable that has the type object or to any interface type implemented by this value type.
int i = 123;
object o = i; // boxing -> reference type
object p = (object)i; // -> reference type - explicit boxing also valid
The result of this statement is creating an object reference o, on the stack, that references a value of the type int, on the heap.
Unboxing converts a Reference Type variable into a Value Type variable by extracting the value from the object.
int i = 123; // a value type
object o = i; // boxing -> reference type
int j = (int)o; // unboxing -> value type
The result of this statement is creating an int value type j, on the stack, that has the value of the references of the object o.
public class Cache { }
public class DiskCache : Cache { }
public class MemoryCache : Cache { }
public class OptimizedDiskCache : DiskCache { }
/**** Valid ****/
/** 1 **/
OptimizedDiskCache optimizedDiskCache = new OptimizedDiskCache();
Cache cache = (Cache) optimizedDiskCache; // Boxing - Cache is parent of OptimizedDiskCache
/** 2 **/
OptimizedDiskCache optimizedDiskCache = new OptimizedDiskCache();
DiskCache diskCache = (DiskCache) optimizedDiskCache; // Boxing - DiskCache is parent of OptimizedDiskCache
/** 3 **/
OptimizedDiskCache optimizedDiskCache = new OptimizedDiskCache();
Cache cache = (Cache) optimizedDiskCache; // Boxing - Cache is parent of OptimizedDiskCache
DiskCache diskCache = (DiskCache) cache; // Unboxing - DiskCache child of Cache and cache boxed reference type child of DiskCache object
/**** Not Valid ****/
/** 1 **/
MemoryCache memoryCache = new MemoryCache();
Cache cache = (Cache) memoryCache; // OK
DiskCache diskCache = (DiskCache) cache; // ERROR - DiskCache child of Cache, cache boxed reference of MemoryCache object but MemoryCache not DiskCache (or children)
/** 2 **/
DiskCache diskCache = new DiskCache();
OptimizedDiskCache optimizedDiskCache = (OptimizedDiskCache) diskCache; // ERROR - Not a boxed reference of OptimizedDiskCache (or children) -> can't unbox
/** 3 **/
Cache cache = new Cache();
MemoryCache memoryCache = (MemoryCache) cache; // ERROR - Not a boxed reference of MemoryCache (or children) -> can't unbox
A generic type parameter allows you to specify an arbitrary type T to a method at compile-time, without specifying a concrete type in the method or class declaration.
List
, SortedList
, HashSet
, Dictionary
, Tuple
, Queue
and Stack
all used generic type parameters.
List
is List<T>
, Dictionary
is Dictionary<TKey, TValue>
, etc.
public class GenericList<T> {
public void Add(T input) { } // Here do nothing but can be used to store input
}
GenericList<int> list1 = new GenericList<int>();
list1.Add(1);
GenericList<string> list2 = new GenericList<string>();
list2.Add("");
The built-in Compare
method use generic type.
public abstract int Compare (T? x, T? y); // return "< 0" if x<y, "= 0" if x=y and "> 0" if x>y
Compare
override public class Box
{
public double Length;
public double Height;
public double Width;
public Box(double l, double h, double w) {
Length = l; Height = h; Width = w;
}
}
public class BoxCompare : Comparer<Box>
{
public override int Compare(Box x, Box y) {
if (x.Length * x.Height * x.Width > y.Length * y.Height * y.Width)
return (1);
else if (x.Length * x.Height * x.Width < y.Length * y.Height * y.Width)
return (-1);
else
return (0);
}
}
Box box1 = new Box(1, 1, 1);
Box box2 = new Box(1, 2, 1);
BoxCompare boxCompare = new BoxCompare();
Console.WriteLine(boxCompare.Compare(box1, box2)); // -1
static void Swap<T>(ref T lhs, ref T rhs) {
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
int a = 1;
int b = 2;
Swap<int>(ref a, ref b); // Swap(ref a, ref b) also works
Console.WriteLine(a + " " + b); // 2 1
Indexers allow instances of a class or struct to be indexed just like arrays. The indexed value can be set or retrieved without explicitly specifying a type or instance member.
class SampleCollection<T> {
private T[] arr = new T[100];
public T this[int i] {
get { return arr[i]; }
set { arr[i] = value; }
}
}
var stringCollection = new SampleCollection<string>();
stringCollection[0] = "First line";
stringCollection[1] = "Second line";
Console.WriteLine(stringCollection[0]); // First line
Console.WriteLine(stringCollection[1]); // Second line
A delegate is a type that represents references to methods with a particular parameter list and return type.
In other word, a delegate represents a template (signature and return type) that a function called by another function must respect.
Example from Windows page on Delegate examples:
public delegate void Del(string message); // delegate
public static void DelegateMethod(string message) { Console.WriteLine(message); } // function that respects delegate template
public static void MethodWithCallback(int param1, int param2, Del callback) {
callback("The number is: " + (param1 + param2).ToString());
}
MethodWithCallback(1, 2, DelegateMethod); // The number is: 3
// Alternative
Del handler = DelegateMethod;
MethodWithCallback(1, 2, handler); // The number is: 3
Func
is a generic delegate included in the System namespace. It has zero or more input parameters and one out parameter. The last parameter specified in the brackets “<>” is the out parameter.
static int Sum(int x, int y) { return x + y; }
Func<int,int, int> add = Sum; // Assign method to delegate - Last int represents the return type
int result = add(10, 10);
Console.WriteLine(result);
Compute numerically the integral of any function is done by calling a function integral that take in argument the mathematical function we want to compute its integral. This function used as parameter is in C# a delegate that can be represente using Func
.
// Integrate takes in input a method that takes a double in input and returns a double
double Integrate(Func<double, double> f, double x_low, double x_high, int N_steps) {
double h = (x_high - x_low) / N_steps;
double res = (f(x_low) + f(x_high)) / 2;
for (int i = 1; i < N_steps; i++)
res += f(x_low + i * h);
return (h * res);
}
double f(double x) => x;
Console.WriteLine(Integrate(f, 0, 10, 100)); // 50
double f(double x) => x*x;
Console.WriteLine(Integrate(f, 0, 10, 100)); // 333.35 (true value : 333.33)
Integrate function from this StackOverflow post.
Action
is a delegate type defined in the System namespace. An Action type delegate is the same as Func delegate except that the Action delegate doesn’t return a value. In other words, an Action delegate can be used with a method that has a void return type.
static void ConsolePrint(int i) { Console.WriteLine(i); }
Action<int> printActionDel = ConsolePrint;
printActionDel(10); // 10
Predicate
represents a method containing a set of criteria and checks whether the passed parameter meets those criteria. A predicate delegate methods must take one input parameter and return a boolean - true or false.
Predicate<string> isUpper = s => s.Equals(s.ToUpper()); // Predicate checks the condition s = s.ToUpper()
bool result = isUpper("hello world!!"); // false
See: