Egna datatyper
Ibland räcker inte int, double och string. Du kanske vill ha en typ som representerar ett belopp, en temperatur eller en enhet — och som beter sig som en inbyggd typ. Det är möjligt genom operator-överlagring och konverteringsoperatorer.
När du läst detta ska du kunna
- Skapa en struct som fungerar som en inbyggd typ
- Definiera implicita konverteringar (
int→ din typ och tillbaka) - Överlagra operatorer som
++,+,>och== - Förklara skillnaden mellan
implicitochexplicitkonvertering
🥷 Ninjakod-varning
Det här är mäktig teknik — och med makt följer ansvar. Operator-överlagring kan göra koden intuitiv eller obegriplig beroende på hur den används.
Använd när: typen representerar ett domänkoncept med tydlig matematik (pengar, längd, temperatur, enheter).
Undvik när: det bara ser coolt ut. En klass med+-operator som gör något oväntat är en buggfälla.
Grundexemplet — Enhet
struct Unit{ private readonly int _value;
private Unit(int value) => _value = value;
// int → Enhet automatiskt public static implicit operator Unit(int value) => new(value);
// Enhet → int automatiskt public static implicit operator int(Unit e) => e._value;
// ++ och -- public static Unit operator ++(Unit e) => e._value + 1; public static Unit operator --(Unit e) => e._value - 1;
public override string ToString() => $"{_value} enheter";}Användning
Unit thing = 5; // implicit int → Unitthing++; // operator++Console.WriteLine(thing); // 6 enheter
Unit a = 3;Unit b = 4;Console.WriteLine(a + b); // 7 enheter (via implicit int-konvertering)Output
6 enheter7 enheterPraktiskt exempel — Valuta
En Kronor-typ med aritmetik och jämförelse:
record struct Kronor(decimal Amount){ public static implicit operator Kronor(decimal value) => new(value); public static implicit operator decimal(Kronor k) => k.Amount;
public static Kronor operator +(Kronor a, Kronor b) => a.Amount + b.Amount; public static Kronor operator -(Kronor a, Kronor b) => a.Amount - b.Amount; public static Kronor operator *(Kronor k, decimal factor) => k.Amount * factor;
public static bool operator >(Kronor a, Kronor b) => a.Amount > b.Amount; public static bool operator <(Kronor a, Kronor b) => a.Amount < b.Amount; public static bool operator >=(Kronor a, Kronor b) => a.Amount >= b.Amount; public static bool operator <=(Kronor a, Kronor b) => a.Amount <= b.Amount;
public override string ToString() => $"{Amount:C}";}
record structger==och!=gratis — bra för värdetyper.
Användning
Kronor price = 199.90m;Kronor tax = price * 0.25m;Kronor total = price + tax;
Console.WriteLine($"Pris: {price}");Console.WriteLine($"Moms: {tax}");Console.WriteLine($"Total: {total}");
if (total > 300m) Console.WriteLine("Fri frakt!");Output
Pris: 199,90 krMoms: 49,98 krTotal: 249,88 krimplicit vs explicit
implicit | explicit | |
|---|---|---|
| Konvertering sker | Automatiskt | Kräver cast: (Type)value |
| Säkert när | Ingen information förloras | Precision eller värde kan förloras |
| Exempel | int → double | double → int (trunkerar) |
struct Celsius{ public double Degrees { get; } public Celsius(double d) => Degrees = d;
// implicit: double → Celsius tappar ingenting public static implicit operator Celsius(double d) => new(d);
// explicit: Celsius → Fahrenheit är en annan skala — var tydlig public static explicit operator Fahrenheit(Celsius c) => new(c.Degrees * 9.0 / 5.0 + 32.0);
public override string ToString() => $"{Degrees:F1} °C";}Celsius boiling = 100.0; // implicitvar fahrenheit = (Fahrenheit)boiling; // explicit castConsole.WriteLine($"{boiling} = {fahrenheit}"); // 100.0 °C = 212.0 °FVilka operatorer kan överlagras?
| Kategori | Operatorer |
|---|---|
| Aritmetik | + - * / % |
| Prefix/postfix | ++ -- |
| Jämförelse | == != < > <= >= (alltid parvis) |
| Unärt | + - ! ~ |
| Logik | true false (ger && och ` |
Jämförelseoperatorer måste definieras parvis:
>kräver<,==kräver!=.
TL;DR
Skapa en struct (eller record struct för värdesemantik) med:
- Implicit konvertering — så typen fungerar naturligt med inbyggda typer
- Operator-överlagring — för aritmetik och jämförelse
ToString()— för läsbar utskrift
Använd det för tydliga domänkoncept. Undvik det för att vara smart.