slama.dev

The C# programming language

19. 2. 2021; lecture notes

Preface

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

Strings

Action Code
split s.Split(char);
split on multiple delimiters s.Split(delimiters);, delimiters is char[]
convert to integer int.Parse(string);, can throw!
length s.Length;

Interning

System.Text.StringBuilder

Interpolation

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

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

Chars

File I/O

Action Code
reading System.IO.StreamReader f = new System.IO.StreamReader(path);
read line f.ReadLine();
read chars int chars_read = f.Read(buffer, 0, BUFFER_SIZE);
writing System.IO.StreamWriter f = new System.IO.StreamWriter(path);
write line f.WriteLine(line);
close f.Dispose();

Classes

Constructor

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;
	}
}
class A : Z {
	int x = something;
	
	A () {stuff}
}

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

class A : Z {
	A () {
		int x = something;
		
		// constructor of Z (without parameters)
		
		stuff
	}
}
class A : Z {
	A () : base(/*parameters for constructor of Z*/) {stuff}
}

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

class A : Z {
	A () {
		int x = something;
		
		// constructor of Z (with the appropriate parameters)
		
		stuff
	}
}

Class constructor

class A {
	static A() { }
}

Inheritance

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
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
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
  A M D B
A.Name A M M M
D.Name     D B
Superclass to subclass conversion
is
as
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)

if (a is B b) {
	// do stuff with `B b`
}

// `b` is not initialized here!
System.Object
System.ValueType
sealed

Variable scope

Local variables

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

Exceptions

System.Exception

Property/Function Meaning
e.Message string error message
e.StackTrace string trace of method call stack
e.Source string app/object that threw it
e.ToString() string the formatted exception

Syntax

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

Type x;
try {
	x = new Type();  // could raise an exception!
	
	// some code
} finally {
	if (x != null) x.Dispose();
}
using (type x = new Type()) {
	// some code
}

// is also equivalent to (since C# 8.0)
// the `Dispose` is called when the variable goes out of scope

using type x = new Type();

Properties

int Property {
	get { /* stuff to do */ }
	set { /* stuff to do (with a variable `value`) */ }
}

Auto-implemented

Instantiating objects with properties

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)

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);
		}
	}
	
}

CLI Type System

Value types

Simple types

Implicit Conversions.

Nullable types

Reference types

Arrays
Action Code
create int[] array = new int[size];
create statically int[] array = {1, 2, 3};
fill with stuff Array.Fill(table, -1, 0, 256);, requires System
sort Array.Sort(array);, highly optimized
length .Length

Pointers

(un)boxing

Structures

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

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

        // A a2 = a;  // is not ok, the entire struct has not been initialized

        a.num2 = 5;

        A a2 = a;  // is now ok
    }
}

readonly

Visibility

Access Modifiers Access is…
public not restricted.
private limited to the containing type.
protected limited to the containing class derived types.
internal limited to the current assembly.
protected internal limited to the current assembly OR same/derived types.
private protected limited to the current assembly AND same/derived types.
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;
	}
}

=>

??, ??=, ?.

ref

void Inc(ref int x) { x += 1; }

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

out

void Read(out int first, out int next) {
	first = Console.Read();
	next = Console.Read();
}

void f() {
	int first, next;
	Read(out first, out next);
}
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

Heaps and GC

Large Object Heap (LOH)

Small Object Heap (SOH)

CIL

GAC

JIT

AOT

CLR

BCL

.NET

Tiered compilation

Self-contained .exe

Method inlining

Demand loading

(De)compiling

Data structures

Dictionaries

Action Code
create Dictionary<int, int> d = new Dictionary<int, int>();
contains d.ContainsKey(element);
add d[index] = element;

Queues

Action Code
create Queue<string> q = new Queue<string>();
add q.Enqueue(element);
pop q.Dequeue(element);
size q.Count;
peek q.Peek();

Miscellaneous

NuGet

BenchmarkDotNet

prg.exe.config (XML)

CLS

Arithmetic overflows

checked {
	// kód
}

typeof(Class)

nameof(x) [Microsoft Docs]

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

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!
		});
	}
}