C# 14: Performance Inkrement-Operatoren
Hin und wieder sind eigene Klassen mit ++ und -- Operatoren notwendig. Das mehr oder weniger große Problem dabei ist dies bisher etwas ... naja, verschwenderisch ist.
Aber C# 14 bringt endlich eine elegante Lösung!
Das alte Problem
Stellen wir uns vor, wir haben eine Counter-Klasse und wollen sie inkrementieren können - quisi quasi das Hello World der Counter
public class Counter
{
private int value;
public static Counter operator ++(Counter c)
{
return new Counter(c.value + 1); // Ups, schon wieder eine neue Instanz...
}
}
Jedes Mal wenn wir ++myCounter schreiben, wird eine komplett neue Instanz erstellt. Bei ein paar Aufrufen - Kein Problem. Aber wenn wir das in einer heißen Schleife machen, dann sammelt sich der Garbage ziemlich schnell an.
Die neue Lösung: Instanz-Operatoren
C# 14 lässt euch die Operatoren als Instanzmethoden definieren:
public class Counter
{
private int value;
// Ta-da! Kein 'static', kein neues Objekt
public void operator ++()
{
value++; // Einfach den vorhandenen Wert ändern
}
public void operator --()
{
value--;
}
}
Was ist anders?
Die neuen Instanz-Operatoren haben ein paar klare Regeln:
public- müssen öffentlich sein (logisch)- Kein
static- sind ja Instanzmethoden voidReturn-Typ - geben nichts zurück, ändern nur die Instanz- Keine Parameter - auch keine mit Default-Werten
Warum ist das so cool?
In Abwandlung von Steve Balmer: "Performance, Performance, Performance!"
Früher:
for (int i = 0; i < 1000000; i++)
{
++myCounter; // 1 Million neue Counter-Objekte...
}
Jetzt:
for (int i = 0; i < 1000000; i++)
{
++myCounter; // Immer das gleiche Objekt, nur der Wert ändert sich
}
Besonders bei Value-ähnlichen Typen wie Koordinaten, Zählern oder mathematischen Objekten ist das ein Game-Changer!
Ein praktisches Beispiel
Hier ein Point-Typ, der jetzt endlich effizient inkrementiert werden kann:
public class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public void operator ++()
{
X++;
Y++;
}
public void operator --()
{
X--;
Y--;
}
}
// Verwendung:
var point = new Point(1, 1);
++point; // point ist jetzt (2, 2)
++point; // point ist jetzt (3, 3)
Wichtiger Hinweis: Instanz-Operatoren ändern den Zustand des Objekts! Das bedeutet, dass wir bei Multi-Threading aufpassen müssen:
// Potenzielle Race-Condition:
Parallel.For(0, 1000, i => ++sharedCounter);
// Besser mit Locking:
public void operator ++()
{
lock (lockObject)
{
value++;
}
}
Happy Coding! 💻