Advanced C# Concepts
Advanced C# Concepts
Advanced C# Concepts
H.Mössenböck
University of Linz, Austria
[email protected]
Contents
• Inheritance
• Interfaces
• Delegates
• Exceptions
• Namespaces and Assemblies
• Attributes
• Threads
• XML Comments
1
Inheritance
2
Syntax
class A { // base class
int a;
public A() {...}
public void F() {...}
}
3
Asignments and Type Checks
class A {...}
class B : A {...}
class C: B {...}
Assignments
A a = new A(); // static type of a: the type specified in the declaration (here A)
// dynamic type of a: the type of the object in a (here also A)
a = new B(); // dynamic type of a is B
a = new C(); // dynamic type of a is C
a = null;
if (a is C) ... // false: if a == null, a is T always returns false
4
Checked Type Casts
Cast
A a = new C();
B b = (B) a; // if (a is B) stat.type(a) is B in this expression; else exception
C c = (C) a;
a = null;
c = (C) a; // ok Î null can be casted to any reference type
as
A a = new C();
B b = a as B; // if (a is B) b = (B)a; else b = null;
C c = a as C;
a = null;
c = a as C; // c == null
5
Overriding of Methods
Only methods that are declared as virtual can be overridden in subclasses
class A {
public void F() {...} // cannot be overridden
public virtual void G() {...} // can be overridden in a subclass
}
class B : A {
public override void WhoAreYou() { Console.WriteLine("I am a B"); }
}
A message invokes the method belonging to the dynamic type of the receiver
(not quite true, see later)
A a = new B();
a.WhoAreYou(); // "I am a B"
Every method that can work with A can also work with B
void Use (A x) {
x.WhoAreYou();
}
7
Hiding
Members can be declared as new in a subclass.
They hide inherited members with the same name.
class A {
public int x;
public void F() {...}
public virtual void G() {...}
}
class B : A {
public new int x;
public new void F() {...}
public new void G() {...}
}
B b = new B();
b.x = ...; // accesses B.x
b.F(); ... b.G(); // calls B.F and B.G
8
Dynamic Binding (with hiding)
class A {
public virtual void WhoAreYou() { Console.WriteLine("I am an A"); }
}
class B : A {
public override void WhoAreYou() { Console.WriteLine("I am a B"); }
}
class C : B {
public new virtual void WhoAreYou() { Console.WriteLine("I am a C"); }
}
class D : C {
public override void WhoAreYou() { Console.WriteLine("I am a D"); }
}
C c = new D();
c.WhoAreYou(); // "I am a D"
A a = new D();
a.WhoAreYou(); // "I am a B" !!
9
Fragile Base Class Problem
Initial situation
class LibraryClass {
public void CleanUp() { ... }
}
class MyClass : LibraryClass {
public void Delete() { ... erase the hard disk ... }
}
OK OK Error! OK
- default constr. A() - A() - no explicit call of - A(int x)
- B(int x) - B(int x) the A() constructor - B(int x)
- default constr. A()
does not exist
11
Visibility protected and internal
protected Visible in declaring class and its subclasses
(more restricive than in Java)
internal Visible in declaring assembly (see later)
protected internal Visible in declaring class, its subclasses and the declaring assembly
Example
class Stack {
protected int[] values = new int[32];
protected int top = -1;
public void Push(int x) {...}
public int Pop() {...}
}
class BetterStack : Stack {
public bool Contains(int x) {
foreach (int y in values) if (x == y) return true;
return false;
}
}
class Client {
Stack s = new Stack();
... s.values[0] ... // compilation error!
}
12
Abstract Classes
Example
abstract class Stream {
public abstract void Write(char ch);
public void WriteString(string s) { foreach (char ch in s) Write(s); }
}
Note
• Abstract methods do not have an implementation.
• Abstract methods are implicitly virtual.
• If a class has abstract methods it must be declared abstract itself.
• One cannot create objects of an abstract class.
13
Abstract Properties and Indexers
Example
abstract class Sequence {
public abstract void Add(object x); // method
public abstract string Name { get; } // property
public abstract object this [int i] { get; set; } // indexer
}
Note
• Overridden indexers and properties must have the same get and set methods as in the
base class
14
Sealed Classes
Example
sealed class Account : Asset {
long val;
public void Deposit (long x) { ... }
public void Withdraw (long x) { ... }
...
}
Note
• sealed classes cannot be extended (same as final classes in Java),
but they can inherit from other classes.
• override methods can be declared as sealed individually.
• Reason:
– Security (avoids inadvertent modification of the class semantics)
– Efficiency (methods can possibly be called using static binding)
15
Interfaces
16
Syntax
public interface IList : ICollection, IEnumerable {
int Add (object value); // methods
bool Contains (object value);
...
bool IsReadOnly { get; } // property
...
object this [int index] { get; set; } // indexer
}
17
Implemented by Classes and Structs
class MyClass : MyBaseClass, IList, ISerializable {
public int Add (object value) {...}
public bool Contains (object value) {...}
...
public bool IsReadOnly { get {...} }
...
public object this [int index] { get {...} set {...} }
}
• A class can inherit from a single base class, but implement multiple interfaces.
A struct cannot inherit from any type, but can implement multiple interfaces.
• Every interface member (method, property, indexer) must be implemented or inherited
from a base class.
• Implemented interface methods must not be declared as override.
• Implemented interface methods can be declared virtual or abstract (i.e. an interface can
be implemented by an abstract class).
18
Working with Interfaces
<<interface>> <<interface>>
MyBaseClass IList ISerializable
MyClass
19
Example
interface ISimpleReader {
int Read(); <<interface>> Terminal
} ISimpleReader Read
Read
interface IReader : ISimpleReader {
void Open(string name);
void Close();
}
<<interface>> File
class Terminal : ISimpleReader { IReader
public int Read() { ... } Read
} Open Open
Close Close
class File : IReader {
public int Read() { ... }
public void Open(string name) { ... }
public void Close() { ... }
}
20
Delegates and Events
21
Delegate = Method Type
Declaration of a delegate type
delegate void Notifier (string sender); // ordinary method signature
// with the keyword delegate
22
Assigning Different Methods
Every matching method can be assigned to a delegate variable
void SayGoodBye(string sender) {
Console.WriteLine("Good bye from " + sender);
}
greetings = new Notifier(SayGoodBye);
Note
• A delegate variable can have the value null (no method assigned).
• If null, a delegate variable must not be called (otherwise exception).
• Delegate variables are first class objects: can be stored in a data structure, passed as
parameter, etc.
23
Creating a Delegate Value
new DelegateType (obj.Method)
24
Multicast Delegates
A delegate variable can hold multiple values at the same time
Notifier greetings;
greetings = new Notifier(SayHello);
greetings += new Notifier(SayGoodBye);
Note
• if the multicast delegate is a function, the value of the last call is returned
• if the multicast delegate has an out parameter, the parameter of the last call is returned
25
Events = Special Delegate Variables
class Model {
public event Notifier notifyViews;
public void Change() { ... notifyViews("Model"); }
}
class View1 {
public View1(Model m) { m.notifyViews += new Notifier(this.Update1); }
void Update1(string sender) { Console.WriteLine(sender + " was changed"); }
}
class View2 {
public View2(Model m) { m.notifyViews += new Notifier(this.Update2); }
void Update2(string sender) { Console.WriteLine(sender + " was changed"); }
}
class Test {
static void Main() {
Model m = new Model(); new View1(m); new View2(m);
m.Change();
}
}
27
try Statement
FileStream s = null;
try {
s = new FileStream(curName, FileMode.Open);
...
} catch (FileNotFoundException e) {
Console.WriteLine("file {0} not found", e.FileName);
} catch (IOException) {
Console.WriteLine("some IO exception occurred");
} catch {
Console.WriteLine("some unknown error occurred");
} finally {
if (s != null) s.Close();
}
28
System.Exception
Properties
e.Message the error message as a string;
set in new Exception(msg);
e.StackTrace trace of the method call stack as a string
e.Source the application or object that threw the exception
e.TargetSite the method object that threw the exception
...
Methods
e.ToString() returns the name of the exception
...
29
Throwing an Exception
By an invalid operation (implicit exception)
Division by 0
Index overflow
Acess via a null reference
...
30
Exception Hierarchy (excerpt)
Exception
SystemException
ArithmeticException
DivideByZeroException
OverflowException
...
NullReferenceException
IndexOutOfRangeException
InvalidCastException
...
ApplicationException
... custom exceptions
...
IOException
FileNotFoundException
DirectoryNotFoundException
...
WebException
...
31
Searching for a catch Clause
F G H
... try { ... ...
F(); G(); H(); throw new FooException(...);
... .... .... ....
} catch (Exc e) {
...
}
Caller chain is traversed backwards until a method with a matching catch clause is found.
If none is found => Program is aborted with a stack trace
Advantage: convenient
Disadvantage: less robust software
32
No Throws Clause in Method Signature
Java
void myMethod() throws IOException {
... throw new IOException(); ...
}
C#
void myMethod() {
... throw new IOException(); ...
}
33
Namespaces and Assemblies
34
C# Namespaces vs. Java Packages
C# Java
A file may contain multiple namespaces A file may contain just 1 package
xxx.cs xxx.java
namespace A {...} package A;
namespace B {...} ...
namespace C {...} ...
Namespaces and classes are not mapped Packages and classes are mapped to
to directories and files directories and files
xxx.cs C.java
namespace A { package A;
class C {...} class C {...}
}
Samples Samples
xxx.cs A
C.java
35
Namespaces vs. Packages (continued)
C# Java
Imports namespaces Imports classes
using System; import java.util.LinkedList;
import java.awt.*;
C1 C2 namespace A
C3 C4 namespace B
icon assembly
sources
A.cs assembly
.exe executable with
B.cs .dll library manifest
modules csc
C.netmodule module
.netmodule without
libraries manifest
D.dll
Only metadata are embedded
/doc:name generates an XML file with the specified name from /// comments
39
Compiler Options
How should libraries and modules be embedded?
/lib:dirpath{,dirpath} specifies the directories, in which libraries are searched that are
referenced by /r.
/addmodule:name {,name} adds the specified modules (e.g. xxx.netmodule) to the generated
assembly.
At run time these modules must be in the same directory as the
assembly to which they belong.
Example
csc /r:MyLib.dll /lib:C:\project A.cs B.cs
40
Examples for Compilations
csc A.cs => A.exe
csc A.cs B.cs C.cs => B.exe (if B.cs contains Main)
csc /out:X.exe A.cs B.cs => X.exe
csc /r:X.dll A.cs B.cs => A.exe (where A or B reference types in X.dll)
41
Attributes
42
Attributes
User-defined metainformation about program elements
• Can be attached to types, members, assemblies, etc.
• Extend predefined attributes such as public, sealed or abstract.
• Are implemented as classes that are derived from System.Attribute.
• Are stored in the metadata of an assembly.
• Often used by CLR services (serialization, remoting, COM interoperability)
• Can be queried at run time.
Example
[Serializable]
class C {...} // makes the class serializable
[Serializable] [Obsolete]
class C {...}
[Serializable, Obsolete]
class C {...}
43
Attribute with Parameters ters ameters
r e
p ar am et e e
m
para pos. par
Example o s it i onal na m
a fter
p e
c om
[Obsolete("Use class C1 instead", IsError=true)] // causes compiler message saying
public class C {...} // that C is obsolete
Valid variants:
[Obsolete]
[Obsolete("some Message")]
[Obsolete("some Message", false)]
[Obsolete("some Message", IsError=false)]
value must be a constant 44
Example: ConditionalAttribute
Allows a conditional call of methods
class C {
Use
[Comment("This is a demo class for Attributes", Author="XX")]
class C { ... }
47
Participating Types (excerpt)
public sealed class Thread {
public static Thread CurrentThread { get; } // static methods
public static void Sleep(int milliSeconds) {...}
...
public Thread(ThreadStart startMethod) {...} // thread creation
public string Name { get; set; } // properties
public ThreadPriority Priority { get; set; }
public ThreadState ThreadState { get; }
public bool IsAlive { get; }
public bool IsBackground { get; set; }
...
public void Start() {...} // methods
public void Suspend() {...}
public void Resume() {...}
public void Join() {...} // caller waits for the thread to die
public void Abort() {...} // throws ThreadAbortException
...
}
public delegate void ThreadStart(); // parameterless void method
public enum ThreadPriority {AboveNormal, BelowNormal, Highest, Lowest, Normal}
public enum ThreadState {Aborted, Running, Stopped, Suspended, Unstarted, ...}
48
Example
using System;
using System.Threading;
class Printer {
char ch;
int sleepTime;
public Printer(char c, int t) {ch = c; sleepTime = t;}
public void Print() {
for (int i = 0; i < 100; i++) {
Console.Write(ch);
Thread.Sleep(sleepTime);
}
}
}
class Test {
static void Main() {
Printer a = new Printer('.', 10);
Printer b = new Printer('*', 100);
new Thread(new ThreadStart(a.Print)).Start();
new Thread(new ThreadStart(b.Print)).Start();
}
}
The program runs until the last thread stops.
49
Thread States
Thread t = new Thread(new ThreadStart(P));
Console.WriteLine("name={0}, priority={1}, state={2}", t.Name, t.Priority, t.ThreadState);
t.Name = "Worker"; t.Priority = ThreadPriority.BelowNormal;
t.Start();
Thread.Sleep(0);
Console.WriteLine("name={0}, priority={1}, state={2}", t.Name, t.Priority, t.ThreadState);
t.Suspend();
Console.WriteLine("state={0}", t.ThreadState);
t.Resume();
Console.WriteLine("state={0}", t.ThreadState);
t.Abort();
Thread.Sleep(0);
Console.WriteLine("state={0}", t.ThreadState);
Output
name=, priority=Normal, state=Unstarted
name=Worker, priority=BelowNormal, state=Running
state=Suspended
state=Running
state=Stopped
50
Example for Join
using System;
using System.Threading;
class Test {
Output
start--------------------end
51
Mutual Exclusion (Synchronization)
lock Statement
lock(Variable) Statement
Example
class Account { // this class should behave like a monitor
long val = 0;
is a shortcut for
Monitor.Enter(v);
try {
Statement
} finally {
Monitor.Exit(v);
}
53
Wait and Pulse
Monitor.Wait(lockedVar); wait() in Java (in Java lockedVar is always this)
Monitor.Pulse(lockedVar); notify() in Java
Monitor.PulseAll(lockedVar); notifyAll() in Java
Example
Thread A Thread B
1 lock(v) { 3 lock(v) {
... ...
2 Monitor.Wait(v); 5 4 Monitor.Pulse(v);
... ...
} }6
54
Example: Synchronized Buffer
class Buffer { If producer is faster
const int size = 4; Put
char[] buf = new char[size]; Put
int head = 0, tail = 0, n = 0; Put
Put
public void Put(char ch) { Get
lock(this) { Put
while (n == size) Monitor.Wait(this); Get
buf[tail] = ch; tail = (tail + 1) % size; n++; ...
Monitor.Pulse(this);
}
} If consumer is faster
Put
public char Get() { Get
lock(this) { Put
while (n == 0) Monitor.Wait(this); Get
char ch = buf[head]; head = (head + 1) % size; ...
n--;
Monitor.Pulse(this);
return ch;
}
}
}
55
XML Comments
56
Special Comments (like javadoc)
Example
/// ... comment ...
class C {
/// ... comment ...
public int f;
57
Example of a Commented Source File
/// <summary> A counter for accumulating values and computing the mean value.</summary>
class Counter {
/// <summary>The accumulated values</summary>
private int value;
58
Generated XML File
<?xml version="1.0"?>
<doc>
<assembly> XML file can be viewed in
<name>MyFile</name> HTML using Visual Studio.
</assembly>
<members>
<member name="T:Counter">
<summary> A counter for accumulating values and computing the mean value.</summary>
</member>
<member name="F:Counter.value">
<summary>The accumulated values</summary> elements are
</member> not nested
<member name="F:Counter.n">
hierarchically!
<summary>The number of added values</summary>
</member>
<member name="M:Counter.Add(System.Int32)">
<summary>Adds a value to the counter</summary>
<param name="x">The value to be added</param>
</member>
<member name="M:Counter.Mean">
<summary>Returns the mean value of all accumulated values</summary>
<returns>The mean value, i.e. <see cref="F:Counter.value"/> / <see cref="F:Counter.n"/></returns>
</member>
</members>
</doc>
59
XML Tags
Predefined Tags
Main tags
<summary> short description of a program element </summary>
<remarks> extensive description of a program element </remarks>
<param name="ParamName"> description of a parameter </param>
<returns> description of the return value </returns>
Tags that are used within other tags
<exception [cref="ExceptionType"]> used in the documentation of a method:
describes an exception </exception>
<example> sample code </example>
<code> arbitrary code </code>
<see cref="ProgramElement"> name of a crossreference link </see>
<paramref name="ParamName"> name of a parameter </paramref>
User-defined Tags
Users may add arbitrary tags, e.g. <author>, <version>, ...
60
Summary
61
Summary of C#
• Familiar
• Safe
– Strong static typing
– Run time checks
– Garbage Collection
– Versioning
• Expressive
– Object-oriented (classes, interfaces, ...)
– Component-oriented (properties, events, assemblies, ...)
– Uniform type system (boxing / unboxing)
– Enumerations
– Delegates
– Indexers
– ref and out parameters
– Value objects on the stack
– Threads and synchronization
– Exceptions
– User attributes
– Reflection
– ...
62