Programming with C#
[Conditional("Debug")] // method will only be available in Debug version
void DoSomeDump(){...}
// not necessary: includes to use library functions/classes
using System;
using System.Windows.Forms;
namespace MyConsole // all items "should" be within a namespace
{
class MyClass
{
// entry point, each function "must" be a member of a class or struct
static int Main (string[] in_commandLineArgs)
{
Console.WriteLine ("Hello, World!");
MessageBox.Show("Hello, World!");
return 0;
}
}
}
class MyClass : MyBaseClass
{
// Constructor
MyClass (int in_num)
: base (in_num) // executes the base class constructor
{...}
// Constructor
MyClass (double in_num)
: this () // executes the 0 param MyClass constructor
{...}
// Default constructor (replaces compiler generated version)
// "private" prevents instantiation from outside
private MyClass(){...}
// static constructor
static MyClass()
{
// init static fields
}
// Any method
public int DoSomething()
{
return 17;
}
// operator overloads always are static methods
public static MyClass operator + (MyClass lhs, MyClass rhs)
{
MyClass ret = new MyClass();
ret.m_strField = lhs.m_strField + rhs.m_strField;
ret.m_intField = lhs.m_intField + rhs.m_intField;
return ret;
}
// regular fields with direct initialization
private string m_strField = "Initial value";
private int m_intField = 36;
// static fields with initialization
private static double s_doubleField = 3.14;
// constant
// set at compile time, cannot be changed within constructor,
// is implicitly static
public const int PI = 3.14;
// readonly constant
// initialized once at runtime within a static constructor
public static readonly int EPSILON;
}
// within class, implementation of Dispose:
public void Dispose()
{
Dispose(true);
// inform Garbage Collector that a call of the destructor
// is no longer necessary and the freeing of managed memory
// need not be delayed to long
GC.SuppressFinalize(this);
}
protected virtual void Dispose (bool disposing)
{
if (disposing)
{
// cleanup of managed resources
}
// cleanup of unmanaged resources
}
~Destructor()
{
// cleanup resources
}
Der Aufruf von Dispose() kann auch automatisch ausgeführt werden
using (MyClass myObject = new MyClass())
{
// use myObejct here
} // myObejct.Dispose() will be called automatically here
MyBaseClass myBaseObject; myBaseObject = new MyDerivedClass(); // each class derives from .NET library class System.Object, which // is represented as "object" within C# syntax object myObject = new MyClass();Überschreiben virtueller und nicht virtueller Methoden:
class MyBaseClass
{
public virtual void DoSomethingVirtual(int in_num) {...}
public void DoSomethingNonVirtual(int in_num) {...}
// a derived class can only be instantiated if all abstract
// methdods have been implemented
public abstract void DoAnythingElse();
}
// Override a virtual and a non virtual function
class MyDerivedClass : MyBaseClass
{
public override void DoSomethingVirtual(int in_num) {...}
public new void DoSomethingNonVirtual(int in_num) {...}
}
// cast can be defined as implicit or explicit
public static implicit operator MyDest (MySource in_source)
{
...
// return MyDest instance
}
Anwendung:
MySource source = new MySource(); // if cast operator was defined "implicit" MyDest dest = source; // if cast operator was defined "explicit" MyDest dest = (MyDest) source;Reaktion bei Fehlschlag der cast-Operation von Basisklasse auf abgeleitete Klasse:
// throws an exception MyDerivedClass derived = (MyDerivedClass) baseRef; // use null instead of exception MyDerivedClass derived as (MyDerivedClass) baseRef; // derived now has value "null"
interface IMyInterface
{
void DoSomething (int in_num);
}
// not allowed: access modifiers, implementation code, virtual, abstract
// deriving from other interface is possible
Implementierung von Interfaces inerhalb einer Klasse:
class MyClass : MyBaseClass, IMyInterface, IMyInterface2
{
// implement interface method
// here we choose to define it as "public virtual"
public virtual void DoSomething (int in_num){...}
}
Prüfung, auf Vorhandensein eines Interfaces zur Laufzeit
IMyInterface myInterface;
myInterface = someObject as IMyInterface;
if (myInterface != null)
{
// interface exists and can be used
}
if (myInt) in C# zwingend: if (myInt != 0)
switch (myString)
{
case "SomeText":
// do something
break;
case "AnotherText";
// do something
goto case "NextCase"; // no implicit fall through allowed,
// if case is non empty
case "NextCase": // implicit fall through is allowed
// for empty case
case "LastCase":
// do something
break;
default:
// do something
break;
}
foreach (int number in myNumberArray)
{
Console.WriteLine (number); // access to elements is READONLY
}
Zum Verändern der Elemente ist eine herkömmliche for-Schleife erforderlich:
for (int i = 0; i< myNumberArray.Length; i++)
{
myNumberArray[i] += 3; // change element
}
double d = double.Parse("3.14"))
string myFilePath = @"C:\MyFolder\MySubFolder"; // double "\\" is not required string multiLineMessage = @"Line 1 Line2 Line3"; // carriage returns are part of the defined string
reference type
MyClass var1; // uninitialized reference var1 = new MyClass(); // new calls default constructor // initializes fields, // and allocates memory on the heap var1.SomeIntField = 17; MyClass var2 = var1; // var2 now points to the same object as var1 var2.SomeIntField = 36; // also changes var1.SomeIntField var2 = null; // var2 does no longer refer to anything // var1 still refers to the objectvalue type
MyStruct myVar; // creates struct on the stack,
// but does not call constructor,
// fields are uninitialized
myVar = new MyStruct(); // new executes default constructor,
// initializes fields,
// no effect on memory allocation,
// already exists on stack
Boxing: Bei Bedarf kann auch ein value type in einen reference type umgewandelt werden:
int i = 33; object boxedI = (object) i; // now use the reference e.g. by calling a method expecting a reference // somewhere else convert back to value type: int k = (int) boxedI; // may throw an exception
Lokale Variablen müssen explizit initialisiert werden:
int myInteger; // will contain random data myInteger = new int(); // now default constructor initializes with 0 // or simpler: int anotherInt = 0;
class MyClass
{
private int m_someInt;
// define property "SomeInt"
// Remark: Omitting set/get is possible and leads to
// a read-only / write-only property
public int SomeInt
{
get
{
return m_someInt;
}
// implicit input param is "value", return type is void
set
{
m_someInt = value;
}
}
}
// definition of method within MyClass public void ChangeNumbers (ref int io_numberOne, ref int io_numberTwo); ... // Calling method ChangeNumbers requires initialization // of ref params and again usage of attribute "ref" int numberOne = 12; int numberTwo = 400; myClass.ChangeNumbers (ref numberOne, ref numberTwo);
// definition of method within MyClass public void CalculateResult (int in_startValue, out int out_result); ... //Calling method CalculateResult does not // require initialization of out param, but again usage of attribute "out" int result; // not initialized myClass.CalculateResult (4711, out result);
// initialized with default constructor, here 0.0,
// the size of the array belongs to the instance not to its type
double [] myArray1 = new double[10];
double [] myArray2 = new double[50];
// explicit initialization
double [] myArray3 = {1.0, 2.0, 3.0, 4.0, 5.0,
6.0, 7.0, 8.0, 9,0, 10.0};
// example for three dimensional rectangular array
// number of elements is 2x3x2 = 12
int [,,] myArray3D;
myArray3D = new int [2,3,2];
// example for two dimensional jagged array
// number of elements can be specific for each row
int [][] myJaggedArray = new int [3][];
for (int = 0; i<3; i++)
myJaggedArray[i] = new int [2*i];
IndexOutOfBounds Exception geworfen
System.Collections.ArrayList möglich
// definition of enum
enum Color {RED, GREEN, BLUE, YELLOW}
// usage requires the enumeration name:
Color myColor = Color.GREEN;
// read value from string
Color myColor = (Color) Enum.Parse (typeof(Color), "YELLOW", true);
try
{
// do something which may cause an exception
// code may contain several calls of return:
// before really returning the finally block is executed!
return;
}
// optionally catch the exception to perform
// some error handling
catch (MyException e) // MyException must be derived from System.Exception
{
// error handling
}
// optionally perform some cleanup operations
// block is also called without preceding catch block
finally
{
// code is executed in any case before method returns
// e.g. free resources allocated within try block
}
public unsafe void SomeMethod(){...}
unsafe class SomeClass(){...}
unsafe {...}
MyClass myObject = new MyClass();
fixed (int *pInt = &myObject.m_someIntField)
{
// use pointer to m_someIntField;
}
Definition eines Delegate:
delegate void MyDelegateFunction (int in_num);Beispielklasse, deren Methode über das Delegate aufgerufen werden soll:
class MyClass
{
void MyMethod (int in_maxNum){...};
}
Beispielmethode, die einen Delegate als Parameter erwartet
void MethodAcceptingDelegate (MyDelegateFunction in_function)
{
// call the method with param 36
in_function(36);
}
Einsatz des Delegate:
MyClass myObject = new MyClass; MyDelegateFunction myFunc = new MyDelegateFunction (myObject.MyMethod) // simply call delegatefucntion myFunc(4711); // pass it to some other method MethodAcceptingDelegate(myFunc);Delegates können mehrere Methoden verkapseln (Verknüpfung mit +=), die dann nacheinander aufgerufen werden.
delegate void MyEventClass(obj sender, EventArgs e);
Deklaration eines Events innerhalb einer Klasse:
public event MyEventClass OnMyEvent;
Verknüpfung des Events mit einer Handlerroutine:
eventSourceObject.OnMyEvent += MyHandlerMethod;
Auslösen des Events in der EventSource-Klasse:
OnMyEvent(this, new EventArgs());
// Definition of custom EventData:
// Notification data delivered together with the PerformanceDataEvent
public class PerformanceDataEventArgs : EventArgs
{
private readonly double m_counterValue;
... // other data and accessor functions
}
// Delegate declaration
// Clients may implement handler methods with this signature:
// The current counter value is delivered
public delegate void EventHandler_PerformanceData(object sender,
PerformanceDataEventArgs e);
// Event source
// Class PerformanceTracker watches an arbitrary system performance counter
// and emits events with the current counter values.
class PerformanceTracker
{
//----- Event -----
// The current counter value is delivered
public event EventHandler_PerformanceData
Event_PerformanceData;
//----- Internal helper method to create and send event -----
protected virtual void RaiseEvent_PerformanceData()
{
EventHandler_PerformanceData handler = Event_PerformanceData;
if (handler != null) // there are really clients registered
{
// store performance data within specific EventArgs
PerformanceDataEventArgs e = new PerformanceDataEventArgs(
m_info, m_currentCounterValue);
// Invokes the delegates, i.e. informs all registered clients
handler(this, e);
}
}
//----- Application code raising event via helper function -----
// Periodic timer handler method
private void RetrievePerformanceData()
{
... // get performance data and store in class atribute
// Inform clients about new counter value
RaiseEvent_PerformanceData();
}
}
// Class which is interested on performance data
// received from class PerformanceTracker
class SomeClient
{
SomeClient()
{
m_performanceTracker = new PerformanceTracker();
// Connect with events from PerformanceTracker
m_performanceTracker.Event_PerformanceData +=
this.NewPerformanceDataReceived;
// Start tracking
m_performanceTracker.StartTracking(m_perfCounterInfo);
// From now on we will receive all performance data through
// event handler routine NewPerformanceDataReceived
}
// Event handler routine to process performance data
public void NewPerformanceDataReceived(object sender, PerformanceDataEventArgs e)
{
// display the received event data somewhere on the GUI
lblCurrentCounterValue.Text = e.m_counterValue.ToString();
}
}