Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä
Mallintakaa C# 6:ssa erottelu-unioni tunniste-enumeraattorilla ja pienillä luokilla, luokaa factory-menetelmiä ja käsitelkää variantit switch-lauseella, jonka oletushaara heittää poikkeuksen.
Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä on ilmainen C# Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/3. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu C# Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C# Academy-kurssilla on yhteensä 3 oppituntia.
DU-ajatus C# 6:ssa
Tavoite: Rakentakaa pieni discriminated union C# 6:lla.
- Tag-enum aktiivisen tapauksen ilmoittamista varten
- Pienet tapausluokat tietoja varten
- Tehdasmetodit kelvollisten tapausten luomista varten
- Switch + default throw kaikkien muunnelmien käsittelyä varten
Tag ja tehdasmetodit
Käyttäkää tag-enumia ja tehdasmetodeja vain kelvollisten tapausten muodostamiseen; muiden tapausten kentät jäävät käyttämättä.
using System;
public enum PaymentKind { Cash, Card, Wire }
public sealed class Payment
{
public PaymentKind Kind;
// per-case data (only one is meaningful per instance)
public string CardLast4; // for Card
public string Iban; // for Wire
private Payment() { }
// factories keep invariants
public static Payment Cash()
{
Payment p = new Payment();
p.Kind = PaymentKind.Cash;
return p;
}
public static Payment Card(string last4)
{
if (string.IsNullOrEmpty(last4) || last4.Length != 4)
throw new ArgumentException("last4 must be 4 digits", "last4");
Payment p = new Payment();
p.Kind = PaymentKind.Card;
p.CardLast4 = last4;
return p;
}
public static Payment Wire(string iban)
{
if (string.IsNullOrEmpty(iban))
throw new ArgumentException("iban must not be empty", "iban");
Payment p = new Payment();
p.Kind = PaymentKind.Wire;
p.Iban = iban;
return p;
}
}
public class Program
{
public static void Main(string[] args)
{
Payment a = Payment.Cash();
Payment b = Payment.Card("1234");
Payment c = Payment.Wire("TR00BANKIBAN");
Console.WriteLine(a.Kind + ", " + b.Kind + ", " + c.Kind);
}
}
Muunnelmien käsittely
Tagiin kohdistuva perinteinen switch tekee käsittelystä selkeää. default throw paljastaa käsittelemättömät muunnelmat testien aikana.
using System;
public enum PaymentKind { Cash, Card, Wire }
public sealed class Payment
{
public PaymentKind Kind;
public string CardLast4;
public string Iban;
public static Payment Cash()
{
Payment p = new Payment(); p.Kind = PaymentKind.Cash; return p;
}
public static Payment Card(string last4)
{
if (string.IsNullOrEmpty(last4) || last4.Length != 4) throw new ArgumentException("last4");
Payment p = new Payment(); p.Kind = PaymentKind.Card; p.CardLast4 = last4; return p;
}
public static Payment Wire(string iban)
{
if (string.IsNullOrEmpty(iban)) throw new ArgumentException("iban");
Payment p = new Payment(); p.Kind = PaymentKind.Wire; p.Iban = iban; return p;
}
}
public static class Exhaustive
{
public static Exception Unhandled(object x)
{
return new InvalidOperationException("Unhandled case: " + x);
}
}
public class Program
{
static string Describe(Payment p)
{
switch (p.Kind)
{
case PaymentKind.Cash: return "Cash";
case PaymentKind.Card: return "Card ****" + p.CardLast4;
case PaymentKind.Wire: return "Wire " + p.Iban;
default: throw Exhaustive.Unhandled(p.Kind);
}
}
public static void Main(string[] args)
{
Console.WriteLine(Describe(Payment.Card("9876")));
}
}
Match-apufunktio (visitor-tyylinen)
Pieni Match-apufunktio keskittää switch-rakenteen ja palauttaa arvon, jolloin kutsukohdat pysyvät selkeinä.
using System;
public enum PaymentKind { Cash, Card, Wire }
public sealed class Payment
{
public PaymentKind Kind;
public string CardLast4;
public string Iban;
public static Payment Cash() { Payment p = new Payment(); p.Kind = PaymentKind.Cash; return p; }
public static Payment Card(string last4) { Payment p = new Payment(); p.Kind = PaymentKind.Card; p.CardLast4 = last4; return p; }
public static Payment Wire(string iban) { Payment p = new Payment(); p.Kind = PaymentKind.Wire; p.Iban = iban; return p; }
}
public static class PaymentMatch
{
public static T Match<T>(
Payment p,
Func<T> onCash,
Func<string, T> onCard,
Func<string, T> onWire)
{
switch (p.Kind)
{
case PaymentKind.Cash: return onCash();
case PaymentKind.Card: return onCard(p.CardLast4);
case PaymentKind.Wire: return onWire(p.Iban);
default: throw new InvalidOperationException("Unhandled: " + p.Kind);
}
}
}
public class Program
{
public static void Main(string[] args)
{
Payment p = Payment.Card("1234");
string summary = PaymentMatch.Match(
p,
delegate { return "Cash"; },
delegate(string last4) { return "Card ****" + last4; },
delegate(string iban) { return "Wire " + iban; }
);
Console.WriteLine(summary);
}
}
Invariantit tehdasmetodeilla
Tehdasmetodit varmistavat invariantit: kukin tapaus alustaa vain sille merkitykselliset kentät, ja virheelliset syötteet hylätään ajoissa.
using System;
public enum ResultKind { Ok, Error }
public sealed class Result
{
public ResultKind Kind;
public string Message; // only for Error
public int Value; // only for Ok
private Result() { }
public static Result Ok(int value)
{
Result r = new Result();
r.Kind = ResultKind.Ok;
r.Value = value;
r.Message = null;
return r;
}
public static Result Error(string message)
{
if (string.IsNullOrEmpty(message)) throw new ArgumentException("message");
Result r = new Result();
r.Kind = ResultKind.Error;
r.Message = message;
r.Value = 0;
return r;
}
}
public class Program
{
static string Show(Result r)
{
switch (r.Kind)
{
case ResultKind.Ok: return "OK: " + r.Value;
case ResultKind.Error: return "ERROR: " + r.Message;
default: throw new InvalidOperationException("Unhandled: " + r.Kind);
}
}
public static void Main(string[] args)
{
Console.WriteLine(Show(Result.Ok(5)));
Console.WriteLine(Show(Result.Error("Boom")));
}
}
Vinkit ja kompromissit
Vinkit:
- Suosikaa pieniä, tarkasti rajattuja tapauksia ja tehdasmetodeja.
- Käsitelkää muunnelmat yhdessä paikassa (switch-apufunktiossa), jotta koodi pysyy DRY-periaatteen mukaisena.
- Pitäkää mukana default throw, jotta puuttuvat tapaukset paljastuvat testeissä.
Kompromissit: Koodia on enemmän kuin moderneissa record-tyypeissä, mutta ratkaisu on selkeä ja yhteensopiva C# 6:n kanssa.
DU:n jäljittelytapa
Kertaus
Kertaus: Mallintakaa muunnelmat tag-enumilla, muodostakaa kelvolliset tapaukset tehdasmetodeilla ja keskittäkää käsittely switch-rakenteeseen (default heittää poikkeuksen), jotta kaikkien tapausten kattavuus varmistuu ajonaikaisesti.
Opi C# tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 93
- Oppitunnit
- 346
Usein kysytyt kysymykset
Onko oppitunti ”Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä” ilmainen?
Kyllä – oppitunnin ”Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko C# Academy-kurssin, päivitä CoddyKit PROhon. C# Academy-kurssilla on yhteensä 3 oppituntia.
Mitä opin oppitunnilla ”Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä”?
Mallintakaa C# 6:ssa erottelu-unioni tunniste-enumeraattorilla ja pienillä luokilla, luokaa factory-menetelmiä ja käsitelkää variantit switch-lauseella, jonka oletushaara heittää poikkeuksen. Harjoittelet C# Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni C# Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin C# Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/3.
Kuinka kauan ”Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä C# Academy-oppitunnilla?
Kyllä. Jokainen C# Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- is-mallit sekä relaatio- ja logiikkamallit (C# 6 -jäljitelmä)
- switch-lausekkeet ja kattavuustarkistukset when-ehdolla (C# 6 -jäljitelmä)
- Toimialuemallinnus erotelluilla unioneilla (record-tyypit) — C# 6 -jäljitelmä