Cobweb

slama.dev

Cobweb

Notes Icon The C# programming language

Preface

This website contains my lecture notes from a lecture by Pavel Ježek from the academic year 2020/2021 (MFF UK). If you find something incorrect/unclear, or would like to contribute, feel free to submit a pull request (or let me know via email).

Besides this, they have been slightly extended by some C#-specific questions for my Bachelor’s state exam that were not covered in the lecture, namely generics and functional elements.

Strings

ActionCode
splits.Split(char);
split on multiple delimiterss.Split(delimiters);, delimiters is char[]
convert to integerint.Parse(string);, can throw!
lengths.Length;

Interning

System.Text.StringBuilder

Interpolation

1
2
3
4
Console.WriteLine("{0}: Hello, {1}!", s1, s2);

// careful, what if s2 == "{0}"
Console.WriteLine("{0}: Hello, " + s2 + "!", s1, s2);

Chars

File I/O

ActionCode
readingSystem.IO.StreamReader f = new System.IO.StreamReader(path);
read linef.ReadLine();
read charsint chars_read = f.Read(buffer, 0, BUFFER_SIZE);
writingSystem.IO.StreamWriter f = new System.IO.StreamWriter(path);
write linef.WriteLine(line);
closef.Dispose();

Classes

Constructor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class A {
	int x = stuff;

	A () {}
}

// is equivalent to (for each constructor!)
// note that stuff can be arbitrary code

class A {
	A () {
		int x = stuff;
	}
}

When inheriting, the constructor of the predecessor is called like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class B : A {
	int x = stuff;

	B () {
		stuff2
	}
}

// is equivalent to (for each constructor!)
// note that stuff can be arbitrary code

class B : A {
	B () {
		int x = stuff;

		// constructor of A (without parameters)

		stuff2
	}
}

If no constructor without parameters exist (for example when a class contains one with parameters, which makes the one without parameters not generate) and we inherit the class without calling it, it won’t compile:

1
2
3
4
5
6
7
8
// THIS WON'T COMPILE!

class A {
	public A(int x) { }
}

class B : A {
}

We have to do this instead:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class A : B {
	A () : base(/*parameters for constructor of B*/) {stuff}
}

// is equivalent to (for each constructor!)
// note that stuff can be arbitrary code

class A : B {
	A () {
		int x = something;

		// constructor of B (with the appropriate parameters)

		stuff
	}
}

Static/class constructor

1
2
3
class A {
	static A() { }
}

Destructors/finalizers

Inheritance

1
2
3
4
5
class A { }      // some stuff
class B : A { }  // some stuff + some more stuff

A a = new A(); // is fine
a = new B();   // is also fine
Virtual/abstract/new methods
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class A {
	public virtual void f() { Console.WriteLine("A"); }
	public virtual void g() { Console.WriteLine("A"); }
}

class B : A {
	public override void f() { Console.WriteLine("B"); }

	// new is optinal, suppresses a warning
	public new void g() { Console.WriteLine("B"); }
}

(new B()).f();  // prints B
(new B()).g();  // prints B

((A)(new B())).f();  // prints B
((A)(new B())).g();  // prints A
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Animal {
	public virtual void Name() { Console.WriteLine("Animal"); }
}

class Mammal: Animal {
	public override void Name() { Console.WriteLine("Mammal"); }
}

class Dog: Mammal {
	// new is optinal, suppresses a warning
	public new virtual void Name() { Console.WriteLine("Dog"); }
}

class Beagle: Dog {
	public override void Name() { Console.WriteLine("Beagle"); }
}

Dog pet = new Beagle();
pet.Name();              // prints Beagle

Animal pet = new Beagle();
pet.Name();              // prints Mammal
AMDB
A.NameAMMM
D.NameDB
Superclass to subclass conversion
is
as
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
B b = a as B;  // assigns a to b if it's of the valid type
               // this is the reason why null is A returns false

if (b != null) {
	// do stuff with B b
}

// is almost equivalent to (since C# 7.0)
// only difference is that b is not initialized after

if (a is B b) {
	// do stuff with B b
}
System.Object
System.ValueType
sealed

Generic classes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class FixedStack<T> {
	T[] a;
	int num;

	public FixedStack(int maxSize) {
		a = new T[maxSize];
	}

	public void push(T val) {
		a[num] = val;
		num += 1;
	}

	public T pop() {
		num -= 1;
		T ret = a[num];
		return ret;
	}
}

Variable scope

Local variables

1
2
if <something> {int b;} else {int b;}  // this is ok
int b;  // this is not (already declared in a nested block)
1
2
3
int e = 1, f;
if (e == 1) {f = 2;}
e = f; // error, f is not initialized in all paths

Exceptions

System.Exception

Property/FunctionMeaning
e.Messagestring error message
e.StackTracestring trace of method call stack
e.Sourcestring app/object that threw it
e.ToString()string the formatted exception

Syntax

1
2
3
4
5
6
7
8
try {
	// stuff
} catch (Exception e) {
	// stuff only executed if the type matches the exception raised
} finally {
	// stuff always executed, even if the exception is not handled
	// for example, for closing IO/network resources
}

Common exception classes


using

1
2
3
4
5
6
7
8
Type x;
try {
	x = new Type();  // could raise an exception!

	// some code
} finally {
	if (x != null) x.Dispose();
}
1
2
3
using (type x = new Type()) {
	// some code
}
1
using type x = new Type();

Properties

1
2
3
4
T Property {
	get { /* stuff to do */ }
	set { /* stuff to do (with a variable value) */ }
}

Auto-implemented

Read-only

Instantiating objects with properties

1
2
3
4
5
6
7
A a = new A { x = 3; y = 6 };

// is literally the same as

A a = new A();
a.x = 3;
a.y = 6;

Parametric properties (indexers)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class File {
	FileStream s;

	public int this [int index] {
		get {
			s.Seek(index, SeekOrigin.Begin);
			return s.ReadByte();
		}

		set {
			s.Seek(index, SeekOrigin.Begin);
			return s.WriteByte((byte) value);
		}
	}

}

Type System

Value types

Simple types

Implicit Conversions.

Nullable types

Reference types

Arrays
ActionCode
createint[] array = new int[size];
create staticallyint[] array = {1, 2, 3};
fill with stuffArray.Fill(table, -1, 0, 256);, requires System
sortArray.Sort(array);, highly optimized
length.Length

(un)boxing

Functional elements

Local functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
static void Main(string[] args) {
	WriteLine("hello");

	double arg(int n) {
		return double.Parse(args[n]);
	}

	double d = arg(0);
	double e = arg(1);
	WriteLine(d + e);
}

Delegates

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using System;

static class Program {
	public delegate bool Condition(int i);

	public static void TestNumbers(Condition condition) {
		for (int i = 0; i < 10; i++) {
			if (condition(i))
				Console.WriteLine(i);
		}
	}

	public bool IsEven(int i) => i % 2 == 0;
	public bool IsOdd(int i) => i % 2 == 1;

	static void Main(string[] args) {
		TestNumbers(IsEven);
	}
}

Lambda funtions

Structures

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

struct A {
    public int num;
    public int num2;
}

struct B {
    public static A a1;
    public A a2;
}

static class Program {
    static void Main(string[] args) {
        B b = new B();
        Console.WriteLine(B.a1.num);  // is ok
        Console.WriteLine(b.a2.num);  // is also ok

        A a;
        Console.WriteLine(a.num);  // is NOT OK
                                   // we haven't called the constructor

        a.num = 5;
        Console.WriteLine(a.num);  // is ok

        A a2 = a;  // is still NOT OK
                   // the entire struct must be initialized

        a.num2 = 5;

        A a3 = a;  // is ok
    }
}

Visibility

Access ModifiersAccess is…
publicnot restricted.
privatelimited to the containing type.
protectedlimited to the containing class derived types.
internallimited to the current assembly.
protected internallimited to the current assembly OR same/derived types.
private protectedlimited to the current assembly AND same/derived types.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class A {
	private int x;

	// is ok, x is private in A
	public int GetX() {
		return x;
	}

	// is ALSO OK, since the code is inside A (B : A)
	public static void SetXOnB(B b) {
		b.x = 30;
	}
}

readonly

=>

??, ??=, ?.

Arithmetic overflows

1
2
3
checked {
	// kód
}

References

ref

1
2
3
4
5
6
void Inc(ref int x) { x += 1; }

void f() {
	int val = 3;
	Inc(ref val);  // val will be 4
}

out

1
2
3
4
5
6
7
8
9
void Read(out int first, out int next) {
	first = Console.Read();
	next = Console.Read();
}

void Main() {
	int first, next;
	Read(out first, out next);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int a;
if (tryParse(something, out a))
	Console.WriteLine("We failed: " + a);

Console.WriteLine("We didn't fail: " + a);

// is the same as

if (tryParse(something, out int a))
	Console.WriteLine("We failed: " + a);

Console.WriteLine("We didn't fail: " + a);

var

Interfaces

1
2
3
4
interface Shape {
	double Perimeter();
	double Area();
}

Implementation details

Heaps and garbage collection

Large Object Heap (LOH)
Small Object Heap (SOH)

Terms to know

CIL

CLR

GAC

JIT

AOT

BCL

.NET

Tiered compilation

CLS

typeof(Class)

nameof(x) [Microsoft Docs]

1
2
3
4
5
6
7
8
9
Console.WriteLine(nameof(System.Collections.Generic));  // output: Generic
Console.WriteLine(nameof(List<int>));                   // output: List
Console.WriteLine(nameof(List<int>.Count));             // output: Count
Console.WriteLine(nameof(List<int>.Add));               // output: Add

var numbers = new List<int> { 1, 2, 3 };
Console.WriteLine(nameof(numbers));        // output: numbers
Console.WriteLine(nameof(numbers.Count));  // output: Count
Console.WriteLine(nameof(numbers.Add));    // output: Add

NUnit tests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using NUnit.Framework;

public class Tests
{
	[SetUp]
	public void Setup() { /* do something for setup (optional) */ }

	[Test]
	public void NameOfTheTest()
	{
		Assert.AreEqual("a", "a");
		Assert.AreNotEqual("a", "b");
		Assert.IsTrue(true);
		Assert.IsFalse(false);

		Assert.Throws<ArgumentException>(() =>
		{
			This doesn't throw!
		});
	}
}

Data structures

Dictionaries

ActionCode
createDictionary<int, int> d = new Dictionary<int, int>();
containsd.ContainsKey(element);
addd[index] = element;

Queues

ActionCode
createQueue<string> q = new Queue<string>();
addq.Enqueue(element);
popq.Dequeue(element);
sizeq.Count;
peekq.Peek();

Acknowledgements