1 softwareentwicklung mit.net teil 2 einführung in c# dr. ralph zeller
TRANSCRIPT
![Page 1: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/1.jpg)
1
Softwareentwicklung mit .NETTeil 2
Einführung in C#
Dr. Ralph Zeller
![Page 2: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/2.jpg)
2
Einleitung
Viele Entwickler wünschen sich eine Programmiersprache, die• so einfach ist wie Visual Basic und
• so mächtig und flexibel wie C++
C# ist die beste Wahl für das .NET Framework
Ideal für• .NET Applikationen
• Web Services
• ...
![Page 3: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/3.jpg)
3
C# Designziele
Erste C/C++ ähnliche komponenten-orientierte Sprache
Garbage Collection
• Keine Speicherlecks oder „wilde Pointer“
Exceptions
• Error Handling von Anfang an bedacht
Typsicherheit
• Keine uninitialisierten Variablen
• Keine unsichere Casts
![Page 4: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/4.jpg)
4
C# Programmstruktur Namespaces
• Enthalten Typdefinitionen und Namespaces
Typdefinitionen
• Klassen, Strukturen, Interfaces, ...
Elemente von Typen• Konstanten, Felder, Methoden, Properties,
Indexer, Events, Operatoren, Konstruktoren, Destruktoren
Organisation der Dateien• Keine Header-Dateien, Programmcode ist “in-line”
• Die Reihenfolge der Deklarationen ist ohne Bedeutung
![Page 5: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/5.jpg)
5
C# Program Strukturusing System;
namespace System.Collections{ public class Stack { Entry top;
public void Push(object data) { top = new Entry(top, data); }
public object Pop() { if (top == null) throw new InvalidOperationException(); object result = top.data; top = top.next; return result; } }}
using System;
namespace System.Collections{ public class Stack { Entry top;
public void Push(object data) { top = new Entry(top, data); }
public object Pop() { if (top == null) throw new InvalidOperationException(); object result = top.data; top = top.next; return result; } }}
![Page 6: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/6.jpg)
6
Statements und Expr. If, while, do benötigen eine boolsche Bedingung
Mit goto kann nicht in Blöcke gesprungen werden
Switch Statement• Kein “fall-through“ im Switch Statement
• “break”, “goto case” or “goto default” notwendig
Checked und unchecked Statement
Ausdrücke müssen etwas tun
if (value) //Fehler WriteLine("true");if (value) //Fehler WriteLine("true");
if (value == 0) //ok WriteLine("true");if (value == 0) //ok WriteLine("true");
![Page 7: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/7.jpg)
7
Foreach Statement
Iteration von Arrays
Iteration durch selbst definierte Collections
public static void Main(string[] args){ foreach (string s in args) Console.WriteLine(s);}
public static void Main(string[] args){ foreach (string s in args) Console.WriteLine(s);}
foreach (Customer c in customers.OrderBy("name")){ if (c.Orders.Count != 0) { ... }}
foreach (Customer c in customers.OrderBy("name")){ if (c.Orders.Count != 0) { ... }}
![Page 8: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/8.jpg)
8
Zwei Arten von Typen
Value (struct) Reference (class)
Variable enthält Wert Referenz
Speicher Stack Heap
Initialisiert mit Alles 0 Konstante: null
Zuweisung kopiert Wert kopiert Referenz
123123jj
tt
123123ii
ss "Hello world""Hello world"
int i = 123;string s = "Hello world";int i = 123;string s = "Hello world";
int j = i;string t = s;int j = i;string t = s;
![Page 9: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/9.jpg)
9
Boxing und Unboxing
Jeder Datentyp kann als Objekt gespeichert oder übergeben werden
123123i
o 123123
System.Int32System.Int32 }} ““Boxing”Boxing”
123123j }} ““Unboxing”Unboxing”
int i = 123;object o = i;int j = (int)o;
int i = 123;object o = i;int j = (int)o;
![Page 10: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/10.jpg)
10
Selbst definierte Typen
Classes (reference)
• Wird für die meisten Objekte verwendet
Structs (value)
• Für Daten-Objekte (Point, Complex, etc.).
Interfaces
![Page 11: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/11.jpg)
11
Classes and Structs
1010
2020spsp
cpcp 1010
2020
CPointCPoint
class CPoint { int x, y; ... }struct SPoint { int x, y; ... }
CPoint cp = new CPoint(10, 20);SPoint sp = new SPoint(10, 20);
class CPoint { int x, y; ... }struct SPoint { int x, y; ... }
CPoint cp = new CPoint(10, 20);SPoint sp = new SPoint(10, 20);
![Page 12: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/12.jpg)
12
Klassen (class)
Einfachvererbung (single inheritance)
Implementierung von beliebig vielen Interfaces
Elemente einer Klasse• Konstanten, Felder, Methoden, Operatoren,
Konstruktoren, Destruktoren
• Properties, Indexer, Events
• Verschachtelte Typen
• Statische Elemente (static)
Zugriffsschutz• public, protected, internal, private
![Page 13: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/13.jpg)
13
Strukturen (struct)
Sind immer “value types“
Ideal für “kleine” Objekte• Keine Allokierung auf dem Heap
• Weniger Arbeit für den Garbage Collector
• Effizientere Speicherbenutzung
• Benutzer können “primitive” Typen selbst erzeugen
• Syntax und Semantik sehr eingängig
• Operator Overloading, Conversion Operators
.NET Framework nutzt diese auch• int, float, double, … sind alles structs
![Page 14: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/14.jpg)
14
Interfaces Enthalten Methoden, Properties, Indexer, und
Events
Explizite Implementierung möglich• Löst Interface Probleme bei Namenskollisionen
• Ausblenden der Implementierung vor dem Benutzer
interface IDataBound{ void Bind(IDataBinder binder);}
class EditBox: Control, IDataBound{ void IDataBound.Bind(IDataBinder binder) {...}}
interface IDataBound{ void Bind(IDataBinder binder);}
class EditBox: Control, IDataBound{ void IDataBound.Bind(IDataBinder binder) {...}}
![Page 15: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/15.jpg)
15
InterfacesBeispiel 1: C# Interfaces
![Page 16: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/16.jpg)
16
Vererbung
Methoden sind standardmäßig NICHT virtual
Eine Methode kann nur mit „override“ überschrieben werden
class B { public virtual void foo() {}}
class D : B { public override void foo() {}}
class B { public virtual void foo() {}}
class D : B { public override void foo() {}}
![Page 17: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/17.jpg)
17
Vererbung
Methoden sind standardmäßig NICHT virtual
Überschreiben einer nicht-virtual Methode Compilerfehler!Außer man verwendet „new“
class N : D { public new void foo() {}}
N n = new N();n.foo(); // call N’s foo((D)n).foo(); // call D’s foo((B)n).foo(); // call D’s foo
class N : D { public new void foo() {}}
N n = new N();n.foo(); // call N’s foo((D)n).foo(); // call D’s foo((B)n).foo(); // call D’s foo
![Page 18: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/18.jpg)
18
Parameterübergabe
in Parameter: Entspricht einer Übergabe „ByVal“. Es wird der Wert an die Methode übergeben
static void Foo(int p) {++p;}Static void Main(){ int x = 8; Foo(x); // Kopie von x wird übergeben Console.WriteLine(x); // x = 8}
static void Foo(int p) {++p;}Static void Main(){ int x = 8; Foo(x); // Kopie von x wird übergeben Console.WriteLine(x); // x = 8}
![Page 19: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/19.jpg)
19
Parameterübergabe
ref Parameter: Man übergibt die Referenz an die Methode
static void Foo(ref int p) {++p;}Static void Main(){ int x = 8; Foo(ref x); // Referenz von x wird übergeben Console.WriteLine(x); // x = 9}
static void Foo(ref int p) {++p;}Static void Main(){ int x = 8; Foo(ref x); // Referenz von x wird übergeben Console.WriteLine(x); // x = 9}
![Page 20: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/20.jpg)
20
Parameterübergabe
out Parameter: Erhält einen Wert von Methode zurück (Variable muss vorher nicht initialisiert werden)
static void Foo(out int p) {p = 3;}Static void Main(){ int x; Foo(out x); // x ist bei Übergabe nicht initialisiert Console.WriteLine(x); // x = 3}
static void Foo(out int p) {p = 3;}Static void Main(){ int x; Foo(out x); // x ist bei Übergabe nicht initialisiert Console.WriteLine(x); // x = 3}
![Page 21: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/21.jpg)
21
Komponentenentwicklung
Was macht eine Komponente aus?• Properties, Methoden, Events
• Design-Time und Run-Time Information
• Integrierte Hilfe und Dokumentation
C# hat die beste Unterstützung• Keine “naming patterns“, Adapter, ...
• Keine externen Dateien
Komponenten sind einfach zu erstellen und zu verwenden
![Page 22: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/22.jpg)
22
Properties
Eine Mischung aus Feldern und Methoden (= smart fields)
Properties sind:• für Read-Only Felder
• für Validierung
• für berechnete oder zusammengesetzte Werte
• Eine Ersatz für Felder in Interfaces
![Page 23: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/23.jpg)
23
Properties Beispielpublic class Button: Control{ private string caption;
public string Caption { get { return caption; } set { caption = value; Repaint(); } }}
public class Button: Control{ private string caption;
public string Caption { get { return caption; } set { caption = value; Repaint(); } }}
Button b = new Button();b.Caption = "OK";String s = b.Caption;
Button b = new Button();b.Caption = "OK";String s = b.Caption;
![Page 24: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/24.jpg)
24
Indexer
Praktische Möglichkeit, Container zu implementieren
Erweitern die Idee der Properties (= smart properties)
Erlauben Indexierung von Daten innerhalb des Objekts
Zugriff ist wie bei Arrays
Der Index selbst kann von jedem Datentyp sein
a = myDict["ABC"];a = myDict["ABC"];
![Page 25: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/25.jpg)
25
Indexer Beispielpublic class ListBox: Control{ private string[] items;
public string this[int index] { get { return items[index]; } set { items[index] = value; Repaint(); } }}
public class ListBox: Control{ private string[] items;
public string this[int index] { get { return items[index]; } set { items[index] = value; Repaint(); } }}
ListBox listBox = new ListBox();listBox[0] = "hello";Console.WriteLine(listBox[0]);
ListBox listBox = new ListBox();listBox[0] = "hello";Console.WriteLine(listBox[0]);
![Page 26: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/26.jpg)
26
Delegates
Ein Delegate Objekt repräsentiert eine Funktion.Dadurch kann ein Delegate als Funktionsparameter oder Mitglied einer Klasse fungieren.
Ersatz für C++ Funktionspointer
Objektorientiert, type-safe und sicher
Grundlage für Events
![Page 27: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/27.jpg)
27
Delegates Beispielusing System;delegate void Delg(string sTry);public class Example1{
// function which uses the delegate object private static void Func1(Delg d){ d("Passed from Func1"); }
// function which is passed as an object private static void Func2(string sToPrint){ Console.WriteLine("{0}",sToPrint); }
// Main execution starts here public static void Main(){ Delg d = new Delg(Func2); Func1(d); }}
using System;delegate void Delg(string sTry);public class Example1{
// function which uses the delegate object private static void Func1(Delg d){ d("Passed from Func1"); }
// function which is passed as an object private static void Func2(string sToPrint){ Console.WriteLine("{0}",sToPrint); }
// Main execution starts here public static void Main(){ Delg d = new Delg(Func2); Func1(d); }}
![Page 28: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/28.jpg)
28
DelegatesBeispiel 2: Check Person
![Page 29: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/29.jpg)
29
Attribute
Runtime / Design-Time Informationen für Typen und deren Elemente
Beispiele
// Klasse serialisierbar machen[Serializable] class MyClass { … }
// Security Einstellungen[assembly:EnvironmentPermissions( SecurityAction.RequestRefuse, UnmanagedCode = true)] namespace Perms { class ReadConfig { … }}
// Klasse serialisierbar machen[Serializable] class MyClass { … }
// Security Einstellungen[assembly:EnvironmentPermissions( SecurityAction.RequestRefuse, UnmanagedCode = true)] namespace Perms { class ReadConfig { … }}
![Page 30: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/30.jpg)
30
Attribute
Für Typen und deren Elemente
Zugriff zur Laufzeit über “reflection“
Vollständig erweiterbar• Ein Attribut ist eine Klasse, die von
System.Attribute abgeleitet wurde
Wird im .NET Framework oft benutzt• XML, Web Services, Security, Serialization,
Component Model, COM und P/Invoke Interop …
![Page 31: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/31.jpg)
31
Beispiele Attribute
Attribute sind Klassen• Abgeleitet von System.Attribute
• Klassenfunktionalität = Attributfunktionalität
public class HelpUrlAttribute : System.Attribute { public HelpUrlAttribute(string url) { … }
public string Url { get {…} } public string Tag { get {…} set {…} } }
public class HelpUrlAttribute : System.Attribute { public HelpUrlAttribute(string url) { … }
public string Url { get {…} } public string Tag { get {…} set {…} } }
![Page 32: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/32.jpg)
32
Attribut verwenden
Wenn der Compiler ein Attribut sieht1. ruft er den Konstruktor auf und übergibt die
Argumente
2. falls weitere Parameter existieren, setze er das Property auf den entsprechenden Wert
3. speichert die Parameter in den Metadaten
[HelpUrl("http://SomeUrl/MyClass")] class MyClass {}
[HelpUrl("http://SomeUrl/MyClass", Tag="ctor")] class MyClass {}
[HelpUrl("http://SomeUrl/MyClass")] class MyClass {}
[HelpUrl("http://SomeUrl/MyClass", Tag="ctor")] class MyClass {}
![Page 33: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/33.jpg)
33
Attribute abfragen
Mittels Reflection können Attribute abgefragt werden
Type type = typeof(MyClass);
foreach(object attr in type.GetCustomAttributes() ) { if ( attr is HelpUrlAttribute ) { HelpUrlAttribute ha = (HelpUrlAttribute) attr;
myBrowser.Navigate( ha.Url ); }}
Type type = typeof(MyClass);
foreach(object attr in type.GetCustomAttributes() ) { if ( attr is HelpUrlAttribute ) { HelpUrlAttribute ha = (HelpUrlAttribute) attr;
myBrowser.Navigate( ha.Url ); }}
![Page 34: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/34.jpg)
34
XML Kommentare
Konsistente Art, um Dokumentation aus dem Code zu erzeugen
"///" Komentare werden exportiert
Dokumentation wird vom Compiler durch /doc: extrahiert werden
Ein „kleines“ Schema ist eingebaut
![Page 35: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/35.jpg)
35
Bsp. XML Kommentareclass XmlElement{ /// <summary> /// Returns the attribute with the given name and /// namespace</summary> /// <param name="name"> /// The name of the attribute</param> /// <param name="ns"> /// The namespace of the attribute, or null if /// the attribute has no namespace</param> /// <return> /// The attribute value, or null if the attribute /// does not exist</return> /// <seealso cref="GetAttr(string)"/> /// public string GetAttr(string name, string ns) { ... }}
class XmlElement{ /// <summary> /// Returns the attribute with the given name and /// namespace</summary> /// <param name="name"> /// The name of the attribute</param> /// <param name="ns"> /// The namespace of the attribute, or null if /// the attribute has no namespace</param> /// <return> /// The attribute value, or null if the attribute /// does not exist</return> /// <seealso cref="GetAttr(string)"/> /// public string GetAttr(string name, string ns) { ... }}
![Page 36: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/36.jpg)
36
C# und Pointer
C# unterstützt• Eingebauter Typ: String
• Benutzerdefinierte Referenztypen
• Große Auswahl an Collection-Klassen
• Referenz- und Ausgabeparameter (out , ref)
99% der Pointer werden nicht mehr benötigt
Dennoch sind Pointer verfügbar, wenn Programmcode mit unsafe markiert ist
![Page 37: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/37.jpg)
37
Beispiel unsafe Codeclass FileStream: Stream{ int handle;
public unsafe int Read(byte[] buffer, int index, int count) { int n = 0; fixed (byte* p = buffer) { ReadFile(handle, p + index, count, &n, null); } return n; }
[DllImport("kernel32.dll", SetLastError=true)] static extern unsafe bool ReadFile(int hFile, void* lpBuffer, int nBytesToRead, int* nBytesRead, Overlapped* lpOverlapped);}
class FileStream: Stream{ int handle;
public unsafe int Read(byte[] buffer, int index, int count) { int n = 0; fixed (byte* p = buffer) { ReadFile(handle, p + index, count, &n, null); } return n; }
[DllImport("kernel32.dll", SetLastError=true)] static extern unsafe bool ReadFile(int hFile, void* lpBuffer, int nBytesToRead, int* nBytesRead, Overlapped* lpOverlapped);}
![Page 38: 1 Softwareentwicklung mit.NET Teil 2 Einführung in C# Dr. Ralph Zeller](https://reader036.vdokument.com/reader036/viewer/2022062512/55204d7349795902118c7b30/html5/thumbnails/38.jpg)
38
Fragen?
Uff...