Algoritmy a programování IV
Chapter contains:
1
PDF
1
Study text
Teacher recommends to study from 19/2/2024 to 25/2/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 26/2/2024 to 3/3/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 4/3/2024 to 10/3/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 11/3/2024 to 17/3/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 18/3/2024 to 24/3/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 25/3/2024 to 31/3/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 1/4/2024 to 7/4/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 8/4/2024 to 14/4/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 15/4/2024 to 21/4/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 22/4/2024 to 28/4/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 29/4/2024 to 5/5/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 6/5/2024 to 12/5/2024.
Chapter contains:
1
Study text
Teacher recommends to study from 13/5/2024 to 19/5/2024.

Týden 1

Studenti si prohloubí znalosti z oblasti programování, a to v jazyce C#. Naučí se pracovat s komponentami, vytvářet grafické aplikace, seznámí se s prací s XML knihovnami, paralelizaci algoritmů, využívat SQL databáze v projektech, vytvářet a používat dynamické knihovny.

Výstupy z učení
Student bude po absolvování předmětu schopen:
- napsat jednoduchý program v C# využívající dynamické knihovny;
- použít komponenty, knihovny XML;
- propojit aplikaci s SQL databází;
- vytvořit algoritmus využívající paralelizaci;
Osnova
  • 1. Práce s WinForm komponenty
  • 2. XAML tvorba grafických aplikací
  • 3. XML knihovny pro práci s XML soubory (Linq, XPath, XDocument)
  • 4. Linq knihovna
  • 5. Delegáti, tvorba více vláknových aplikací, paralelizace, vícevláknové vs. víceprocesové aplikace
  • 6. Tvorba a užití DLL
  • 7. MS SQL databáze a využití v projektech
Literatura

    povinná literatura
  • Microsoft. Průvodce programováním C# [online]. Microsoft.com. Dostupné na: https://docs.microsoft.com/cscz/ dotnet/csharp/programming-guide/index
  • Programování C + +, Blahuta Jiří, MVŠO
    Error: The referenced object does not exist or you do not have the right to read.
    https://is.slu.cz/el/fpf/leto2024/UIN2035/4605218/Programovani_Blahuta_Opory_rSLU.pdf
    doporučená literatura
  • https://stackoverflow.com
  • http://msdn.microsoft.com, http://www.itnetwork.cz
  • CLARK, Dan. Beginning C# Object-Oriented Programming. Second edition. New York: Apress, 2013. ISBN 978-1-4302-4935-1. info
  • Sharp, J. Microsoft Visual C# 2010. 2013. ISBN 978-80-251-3147-3. info
  • BISHOP, J M. C#: návrhové vzory. Brno: Zoner Press, 2010. Encyklopedie Zoner Press. ISBN 978-80-7413-076-2. Brno: Zoner Pres, 2010. ISBN 978-80-7413-076-2. info
  • Nagel, C., a kolektiv. C# 2008 programujeme profesionálně. 2009. ISBN 9788025124017. info
  • Virius Miroslav. C# pro zelenáče. Praha: Neocortex, 2002. ISBN 80-86330-11-7. info

Týden 2

Vytvořte si svoji aplikaci

Pomocí okna terminálu vytvořte adresář s názvem classes. V něm sestavíte aplikaci. Přejděte do daného adresáře a v okně konzoly zadejte dotnet new console . Tento příkaz vytvoří vaši aplikaci. Otevřete soubor Program.cs. Měl by vypadat takto:

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

V tomto kurzu vytvoříte nové typy, které představují bankovní účet. Vývojáři obvykle definují každou třídu v jiném textovém souboru. To usnadňuje správu s rostoucí velikostí programu. V adresáři Classes vytvořte nový soubor s názvem BankAccount.cs.

Tento soubor bude obsahovat definici bankovního účtu. Objektově orientované programování uspořádá kód tak, že vytváří typy ve formě tříd. Tyto třídy obsahují kód, který představuje konkrétní entitu. Třída BankAccount představuje bankovní účet. Kód implementuje specifické operace prostřednictvím metod a vlastností. V tomto kurzu bankovní účet podporuje toto chování:

  1. Má 10místné číslo, které jednoznačně identifikuje bankovní účet.
  2. Obsahuje řetězec, ve kterém jsou uložena jména nebo jména vlastníků.
  3. Zůstatek je možné načíst.
  4. Přijímá vklady.
  5. Akceptuje výběry.
  6. Počáteční zůstatek musí být kladný.
  7. Výběry nemohou vést k zápornému zůstatku.

Definování typu bankovního účtu

Můžete začít vytvořením základů třídy, která toto chování definuje. Vytvořte nový soubor pomocí příkazu Soubor:Nový . Pojmenujte ho BankAccount.cs. Do souboru BankAccount.cs přidejte následující kód:

C#
namespace Classes;public class BankAccount
{
    public string Number { get; }
    public string Owner { get; set; }
    public decimal Balance { get; }    public void MakeDeposit(decimal amount, DateTime date, string note)
    {
    }    public void MakeWithdrawal(decimal amount, DateTime date, string note)
    {
    }
}

Než se pustíme do toho, pojďme se podívat, co jste vytvořili. Deklarace namespace poskytuje způsob, jak logicky uspořádat kód. Tento kurz je relativně malý, takže veškerý kód umístíte do jednoho oboru názvů.

public class BankAccount definuje třídu nebo typ, který vytváříte. Všechno uvnitř { a } , které následuje po deklaraci třídy, definuje stav a chování třídy. Třída má pět členůBankAccount. První tři jsou vlastnosti. Vlastnosti jsou datové prvky a mohou obsahovat kód, který vynucuje ověření nebo jiná pravidla. Poslední dvě jsou metody. Metody jsou bloky kódu, které provádějí jednu funkci. Čtení jmen jednotlivých členů by vám nebo jinému vývojáři mělo poskytnout dostatek informací, abyste pochopili, co třída dělá.

Otevřít nový účet

První funkcí, kterou je potřeba implementovat, je otevření bankovního účtu. Když zákazník otevře účet, musí zadat počáteční zůstatek a informace o vlastníkovi nebo vlastnících tohoto účtu.

Vytvoření nového objektu BankAccount typu znamená definování konstruktoru , který tyto hodnoty přiřadí. Konstruktor je člen, který má stejný název jako třída. Používá se k inicializaci objektů tohoto typu třídy. Do typu přidejte následující konstruktor BankAccount . Nad deklaraci MakeDepositumístěte následující kód :

public BankAccount(string name, decimal initialBalance)
{
    this.Owner = name;
    this.Balance = initialBalance;
}

Předchozí kód identifikuje vlastnosti objektu vytvářeného zahrnutím kvalifikátoru this . Tento kvalifikátor je obvykle volitelný a vynechán. Mohli jste také napsat:


public BankAccount(string name, decimal initialBalance)
{
    Owner = name;
    Balance = initialBalance;
}

Kvalifikátor this je povinný pouze v případě, že místní proměnná nebo parametr má stejný název jako dané pole nebo vlastnost. Pokud this to není nutné, je kvalifikátor ve zbývající části tohoto článku vynechán.

Konstruktory se volají při vytváření objektu pomocí new. Nahraďte řádek Console.WriteLine("Hello World!"); v souboru Program.cs následujícím kódem (nahraďte <name> svým jménem):


", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">using Classes;var account = new BankAccount("<name>", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");

Pojďme se pustit do toho, co jste zatím vytvořili. Pokud používáte Visual Studio, vyberte v nabídce Laditmožnost Spustit bez ladění. Pokud používáte příkazový řádek, zadejte dotnet run adresář, ve kterém jste projekt vytvořili.

Všimli jste si, že číslo účtu je prázdné? Je čas to napravit. Číslo účtu by mělo být přiřazeno při vytváření objektu. Vytvoření by ale nemělo být na volajícím. Kód BankAccount třídy by měl vědět, jak přiřadit nová čísla účtů. Jednoduchým způsobem je začít desetimístným číslem. Zvyšte ho při vytváření každého nového účtu. Nakonec při vytváření objektu uložte číslo aktuálního účtu.

Přidejte deklaraci členu do BankAccount třídy . Za levou složenou závorku { na začátek třídy umístěte BankAccount následující řádek kódu:


private static int s_accountNumberSeed = 1234567890;

Je accountNumberSeed datový člen. Je to private, což znamená, že k němu může přistupovat pouze kód uvnitř BankAccount třídy . Jedná se o způsob oddělení veřejné odpovědnosti (například číslo účtu) od privátní implementace (jak se generují čísla účtů). Je také static, což znamená, že ho BankAccount sdílejí všechny objekty. Hodnota nestatické proměnné je pro každou instanci objektu jedinečná BankAccount . Je accountNumberSeedprivate static pole, a proto má předponu s_ podle konvencí vytváření názvů v jazyce C#. Pole s s popisem static a _ popisem private . Přidejte následující dva řádky do konstruktoru pro přiřazení čísla účtu. Umístěte je za řádek s textem this.Balance = initialBalance:


Number = s_accountNumberSeed.ToString();
s_accountNumberSeed++;

Pokud chcete zobrazit výsledky, zadejte dotnet run .

Vytvoření vkladů a výběrů

Vaše třída bankovního účtu musí přijímat vklady a výběry, aby fungovala správně. Pojďme implementovat vklady a výběry vytvořením deníku každé transakce pro účet. Sledování každé transakce má několik výhod oproti jednoduché aktualizaci zůstatku na každé transakci. Historii lze použít k auditu všech transakcí a správě denních zůstatků. Výpočet zůstatku z historie všech transakcí v případě potřeby zajistí, že všechny chyby v jedné transakci, které jsou opravené, se správně projeví ve zůstatku při dalším výpočtu.

Začněme vytvořením nového typu, který bude představovat transakci. Transakce je jednoduchý typ, který nemá žádnou odpovědnost. Potřebuje několik vlastností. Vytvořte nový soubor s názvem Transaction.cs. Přidejte do ní následující kód:


namespace Classes;public class Transaction
{
    public decimal Amount { get; }
    public DateTime Date { get; }
    public string Notes { get; }    public Transaction(decimal amount, DateTime date, string note)
    {
        Amount = amount;
        Date = date;
        Notes = note;
    }
}

Teď do třídy přidáme List<T>Transaction objekty BankAccount . Za konstruktor v souboru BankAccount.cs přidejte následující deklaraci:


 _allTransactions = new List();
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private List<Transaction> _allTransactions = new List<Transaction>();

Teď správně vypočítáme Balance. Aktuální zůstatek lze najít součtem hodnot všech transakcí. Vzhledem k tomu, že kód je aktuálně, můžete získat jenom počáteční zůstatek na účtu, takže budete muset vlastnost aktualizovat Balance . Nahraďte řádek public decimal Balance { get; } v souboru BankAccount.cs následujícím kódem:


public decimal Balance
{
    get
    {
        decimal balance = 0;
        foreach (var item in _allTransactions)
        {
            balance += item.Amount;
        }        return balance;
    }
}

Tento příklad ukazuje důležitý aspekt vlastností. Teď počítáte zůstatek, když o hodnotu požádá jiný programátor. Váš výpočet vypočítá všechny transakce a poskytne součet jako aktuální zůstatek.

Týden 3

Dále implementujte MakeDeposit metody a MakeWithdrawal . Tyto metody vynucují poslední dvě pravidla: počáteční zůstatek musí být kladný a žádné stažení nesmí vytvořit záporný zůstatek.

Tato pravidla zavádějí koncept výjimek. Standardní způsob, jak indikovat, že metoda nemůže úspěšně dokončit svou práci, je vyvolat výjimku. Typ výjimky a zpráva, která je k ní přidružená, popisují chybu. Zde metoda vyvolá výjimku, MakeDeposit pokud výše vkladu není větší než 0. Metoda MakeWithdrawal vyvolá výjimku, pokud částka výběru není větší než 0 nebo pokud použití výběru vede k zápornému zůstatku. Za deklaraci _allTransactions seznamu přidejte následující kód:


public void MakeDeposit(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
    }
    var deposit = new Transaction(amount, date, note);
    _allTransactions.Add(deposit);
}public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    }
    if (Balance - amount < 0)
    {
        throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    }
    var withdrawal = new Transaction(-amount, date, note);
    _allTransactions.Add(withdrawal);
}

Příkazthrowvyvolá výjimku. Provádění aktuálního bloku končí a řídí přenosy do prvního odpovídajícího catch bloku nalezeného v zásobníku volání. O něco později přidáte catch blok pro otestování tohoto kódu.

Konstruktor by měl získat jednu změnu, aby přidal počáteční transakci místo přímé aktualizace zůstatku. Vzhledem k tomu, že jste již napsali metodu MakeDeposit , zavolejte ji z konstruktoru. Dokončený konstruktor by měl vypadat takto:


public BankAccount(string name, decimal initialBalance)
{
    Number = s_accountNumberSeed.ToString();
    s_accountNumberSeed++;    Owner = name;
    MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}

DateTime.Now je vlastnost, která vrací aktuální datum a čas. Otestujte tento kód přidáním několika vkladů a výběrů do metody Main podle kódu, který vytvoří nový BankAccount:


account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(100, DateTime.Now, "Friend paid me back");
Console.WriteLine(account.Balance);

Dále otestujte, že zachytáváte chybové stavy tím, že se pokusíte vytvořit účet se záporným zůstatkem. Za předchozí kód, který jste právě přidali, přidejte následující kód:


// Test that the initial balances must be positive.
BankAccount invalidAccount;
try
{
    invalidAccount = new BankAccount("invalid", -55);
}
catch (ArgumentOutOfRangeException e)
{
    Console.WriteLine("Exception caught creating account with negative balance");
    Console.WriteLine(e.ToString());
    return;
}

Pomocítry-catch příkazu označíte blok kódu, který může vyvolat výjimky, a zachytíte chyby, které očekáváte. Stejný postup můžete použít k otestování kódu, který vyvolá výjimku pro záporný zůstatek. Před deklaraci invalidAccount ve vaší Main metodě přidejte následující kód:


// Test for a negative balance.
try
{
    account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw");
}
catch (InvalidOperationException e)
{
    Console.WriteLine("Exception caught trying to overdraw");
    Console.WriteLine(e.ToString());
}

Uložte soubor a zadejte dotnet run , abyste ho vyzkoušeli.

Výzva – protokolování všech transakcí

Chcete-li dokončit tento kurz, můžete napsat metodu GetAccountHistory , která vytvoří string pro historii transakcí. Přidejte tuto metodu do BankAccount typu:


public string GetAccountHistory()
{
    var report = new System.Text.StringBuilder();    decimal balance = 0;
    report.AppendLine("Date\t\tAmount\tBalance\tNote");
    foreach (var item in _allTransactions)
    {
        balance += item.Amount;
        report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
    }    return report.ToString();
}

Historie používá StringBuilder třídu k formátování řetězce, který obsahuje jeden řádek pro každou transakci. Kód formátování řetězců jste viděli dříve v těchto kurzech. Jeden nový znak je \t. Tím se vloží karta pro formátování výstupu.

Přidejte tento řádek a otestujte ho v souboru Program.cs:


Console.WriteLine(account.GetAccountHistory());

Výsledky zobrazíte spuštěním programu.

Týden 4

C# je objektově orientovaný programovací jazyk. Čtyři základní principy objektově orientovaného programování jsou:

  • Abstrakce Modelování relevantních atributů a interakcí entit jako tříd za účelem definování abstraktní reprezentace systému
  • Zapouzdření Skrytí interního stavu a funkčnosti objektu a povolení přístupu pouze prostřednictvím veřejné sady funkcí
  • Dědičnosti Možnost vytvářet nové abstrakce na základě existujících abstrakcí.
  • Polymorfismus Schopnost implementovat zděděné vlastnosti nebo metody různými způsoby napříč více abstrakcemi.

V předchozím kurzu jste viděli úvod do třídjak abstrakci , tak zapouzdření. Třída BankAccount poskytla abstrakci pro koncept bankovního účtu. Můžete upravit jeho implementaci, aniž by to mělo vliv na kód, který používal BankAccount třídu . BankAccount Třídy a Transaction poskytují zapouzdření komponent potřebných k popisu těchto konceptů v kódu.

V tomto kurzu tuto aplikaci rozšíříte tak, aby využívala dědičnost a polymorfismus k přidání nových funkcí. Do třídy také přidáte funkce BankAccount s využitím technik abstrakce a zapouzdření , které jste se naučili v předchozím kurzu.

Vytvoření různých typů účtů

Po vytvoření tohoto programu obdržíte žádosti o přidání funkcí do tohoto programu. Funguje to skvěle v situaci, kdy existuje pouze jeden typ bankovního účtu. V průběhu času se vyžadují změny potřeb a související typy účtů:

  • Účet pro příjmy z úroků, na který se načítá úrok na konci každého měsíce.
  • Úvěrový řádek, který může mít záporný zůstatek, ale pokud je zůstatek, každý měsíc se účtuje úrok.
  • Předplacený účet dárkové karty, který začíná jediným vkladem a dá se splácit jenom Může se znovu naplnit jednou na začátku každého měsíce.

Všechny tyto různé účty jsou podobné BankAccount třídě definované v předchozím kurzu. Tento kód můžete zkopírovat, přejmenovat třídy a provést úpravy. Tato technika by fungovala krátkodobě, ale v průběhu času by to bylo více práce. Všechny změny se zkopírují do všech ovlivněných tříd.

Místo toho můžete vytvořit nové typy bankovních účtů, které dědí metody a data z BankAccount třídy vytvořené v předchozím kurzu. Tyto nové třídy mohou rozšířit BankAccount třídu o konkrétní chování potřebné pro každý typ:


public class InterestEarningAccount : BankAccount
{
}public class LineOfCreditAccount : BankAccount
{
}public class GiftCardAccount : BankAccount
{
}

Každá z těchto tříd dědí sdílené chování ze své sdílené základní třídyBankAccount třídy. Napište implementace pro nové a různé funkce v každé z odvozených tříd. Tyto odvozené třídy již mají veškeré chování definované ve BankAccount třídě .

Je vhodné vytvořit každou novou třídu v jiném zdrojovém souboru. V sadě Visual Studio můžete kliknout pravým tlačítkem na projekt a vybrat přidat třídu a přidat novou třídu do nového souboru. V editoru Visual Studio Code vyberte File (Soubor ) a pak New (Nový ) a vytvořte nový zdrojový soubor. V obou nástrojích pojmenujte soubor tak, aby odpovídal třídě : InterestEarningAccount.csLineOfCreditAccount.cs a GiftCardAccount.cs.

Když vytvoříte třídy, jak je znázorněno v předchozí ukázce, zjistíte, že se žádná z odvozených tříd nekompiluje. Konstruktor je zodpovědný za inicializaci objektu. Konstruktor odvozené třídy musí inicializovat odvozenou třídu a poskytnout pokyny, jak inicializovat objekt základní třídy zahrnutý v odvozené třídě. Správná inicializace obvykle probíhá bez jakéhokoli dalšího kódu. Třída BankAccount deklaruje jeden veřejný konstruktor s následujícím podpisem:


public BankAccount(string name, decimal initialBalance)

Kompilátor negeneruje výchozí konstruktor, když konstruktor definujete sami. To znamená, že každá odvozená třída musí explicitně volat tento konstruktor. Deklarujete konstruktor, který může předat argumenty konstruktoru základní třídy. Následující kód ukazuje konstruktor pro InterestEarningAccount:


public InterestEarningAccount(string name, decimal initialBalance) : base(name, initialBalance)
{
}

Parametry tohoto nového konstruktoru odpovídají typu parametru a názvům konstruktoru základní třídy. Syntaxi : base() použijete k označení volání konstruktoru základní třídy. Některé třídy definují více konstruktorů a tato syntaxe umožňuje vybrat, který konstruktor základní třídy voláte. Po aktualizaci konstruktorů můžete vyvinout kód pro každou odvozenou třídu. Požadavky na nové třídy lze uvést takto:

  • Účet pro získání úroků:
    • Získá kredit ve hodnotě 2 % zůstatku na konci měsíce.
  • Úvěrový řádek:
    • Může mít záporný zůstatek, ale nesmí být vyšší v absolutní hodnotě, než je úvěrový limit.
    • Každý měsíc, kdy zůstatek na konci měsíce není 0, se bude účtovat poplatek za úrok.
    • Za každý výběr, který překročí úvěrový limit, se bude účtovat poplatek.
  • Účet dárkové karty:
    • Určitou částku je možné znovu naplnit jednou měsíčně, a to poslední den v měsíci.

Vidíte, že všechny tři tyto typy účtů mají akci, která se provede na konci každého měsíce. Každý typ účtu ale dělá jiné úkoly. K implementaci tohoto kódu použijete polymorfismus . Vytvořte jednu virtual metodu BankAccount ve třídě :


public virtual void PerformMonthEndTransactions() { }

Předchozí kód ukazuje, jak pomocí klíčového virtual slova deklarovat metodu v základní třídě, pro kterou může odvozená třída poskytnout jinou implementaci. Metoda virtual je metoda, ve které se může libovolná odvozená třída rozhodnout provést znovu. Odvozené třídy používají override klíčové slovo k definování nové implementace. Obvykle se to označuje jako "přepsání implementace základní třídy". Klíčové virtual slovo určuje, že odvozené třídy mohou přepsat chování. Můžete také deklarovat abstract metody, kde odvozené třídy musí přepsat chování. Základní třída neposkytuje implementaci metody abstract . Dále musíte definovat implementaci pro dvě z nových tříd, které jste vytvořili. Začněte s InterestEarningAccount:


 500m)
    {
        decimal interest = Balance * 0.02m;
        MakeDeposit(interest, DateTime.Now, "apply monthly interest");
    }
}
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">public override void PerformMonthEndTransactions()
{
    if (Balance > 500m)
    {
        decimal interest = Balance * 0.02m;
        MakeDeposit(interest, DateTime.Now, "apply monthly interest");
    }
}

Do přidejte následující kód LineOfCreditAccount. Kód neguje zůstatek pro výpočet kladného úroku, který se stahuje z účtu:


public override void PerformMonthEndTransactions()
{
    if (Balance < 0)
    {
        // Negate the balance to get a positive interest charge:
        decimal interest = -Balance * 0.07m;
        MakeWithdrawal(interest, DateTime.Now, "Charge monthly interest");
    }
}

Třída GiftCardAccount potřebuje dvě změny, aby implementovala funkci na konci měsíce. Nejprve upravte konstruktor tak, aby zahrnoval volitelnou částku, která se má přičítat každý měsíc:


 _monthlyDeposit = monthlyDeposit;
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private readonly decimal _monthlyDeposit = 0m;public GiftCardAccount(string name, decimal initialBalance, decimal monthlyDeposit = 0) : base(name, initialBalance)
    => _monthlyDeposit = monthlyDeposit;

Konstruktor poskytuje výchozí hodnotu pro monthlyDeposit hodnotu, takže volající mohou vynechat 0 pro žádný měsíční vklad. Dále přepište metodu PerformMonthEndTransactions pro přidání měsíčního vkladu, pokud byla v konstruktoru nastavena na nenulovou hodnotu:


public override void PerformMonthEndTransactions()
{
    if (_monthlyDeposit != 0)
    {
        MakeDeposit(_monthlyDeposit, DateTime.Now, "Add monthly deposit");
    }
}

Přepsání použije měsíční vklad nastavený v konstruktoru. Do metody přidejte Main následující kód, který otestuje tyto změny pro GiftCardAccount a :InterestEarningAccount


var giftCard = new GiftCardAccount("gift card", 100, 50);
giftCard.MakeWithdrawal(20, DateTime.Now, "get expensive coffee");
giftCard.MakeWithdrawal(50, DateTime.Now, "buy groceries");
giftCard.PerformMonthEndTransactions();
// can make additional deposits:
giftCard.MakeDeposit(27.50m, DateTime.Now, "add some additional spending money");
Console.WriteLine(giftCard.GetAccountHistory());var savings = new InterestEarningAccount("savings account", 10000);
savings.MakeDeposit(750, DateTime.Now, "save some money");
savings.MakeDeposit(1250, DateTime.Now, "Add more savings");
savings.MakeWithdrawal(250, DateTime.Now, "Needed to pay monthly bills");
savings.PerformMonthEndTransactions();
Console.WriteLine(savings.GetAccountHistory());

Ověřte výsledky. Teď přidejte podobnou sadu testovacích kódů pro LineOfCreditAccount:

C#
var lineOfCredit = new LineOfCreditAccount("line of credit", 0);
// How much is too much to borrow?
lineOfCredit.MakeWithdrawal(1000m, DateTime.Now, "Take out monthly advance");
lineOfCredit.MakeDeposit(50m, DateTime.Now, "Pay back small amount");
lineOfCredit.MakeWithdrawal(5000m, DateTime.Now, "Emergency funds for repairs");
lineOfCredit.MakeDeposit(150m, DateTime.Now, "Partial restoration on repairs");
lineOfCredit.PerformMonthEndTransactions();
Console.WriteLine(lineOfCredit.GetAccountHistory());

Když přidáte předchozí kód a spustíte program, zobrazí se něco jako následující chyba:

Konzola
Unhandled exception. System.ArgumentOutOfRangeException: Amount of deposit must be positive (Parameter 'amount')
   at OOProgramming.BankAccount.MakeDeposit(Decimal amount, DateTime date, String note) in BankAccount.cs:line 42
   at OOProgramming.BankAccount..ctor(String name, Decimal initialBalance) in BankAccount.cs:line 31
   at OOProgramming.LineOfCreditAccount..ctor(String name, Decimal initialBalance) in LineOfCreditAccount.cs:line 9
   at OOProgramming.Program.Main(String[] args) in Program.cs:line 29

Začněme přidáním druhého konstruktoru, který obsahuje volitelný minimumBalance parametr. Tento nový konstruktor provádí všechny akce provedené existujícím konstruktorem. Nastaví také vlastnost minimálního zůstatku. Můžete zkopírovat tělo existujícího konstruktoru, ale to znamená, že se v budoucnu změní dvě umístění. Místo toho můžete použít zřetězování konstruktoru , aby jeden konstruktor volal jiný. Následující kód ukazuje dva konstruktory a nové další pole:


 0)
        MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private readonly decimal _minimumBalance;public BankAccount(string name, decimal initialBalance) : this(name, initialBalance, 0) { }public BankAccount(string name, decimal initialBalance, decimal minimumBalance)
{
    Number = s_accountNumberSeed.ToString();
    s_accountNumberSeed++;    Owner = name;
    _minimumBalance = minimumBalance;
    if (initialBalance > 0)
        MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}

Předchozí kód ukazuje dvě nové techniky. Nejprve se pole označí minimumBalance jako readonly. To znamená, že hodnotu nelze po vytvoření objektu změnit. Jakmile je BankAccount objekt vytvořený, nemůže se minimumBalance změnit. Za druhé konstruktor, který přebírá dva parametry, používá : this(name, initialBalance, 0) { } jako svou implementaci. Výraz : this() volá druhý konstruktor, ten se třemi parametry. Tato technika umožňuje mít jednu implementaci pro inicializaci objektu, i když klientský kód může zvolit jeden z mnoha konstruktorů.

Tato implementace volá MakeDeposit pouze v případě, že počáteční zůstatek je větší než 0. Tím se zachová pravidlo, že vklady musí být kladné, ale umožní otevření úvěrového účtu se zůstatkem 0 .

Teď, když BankAccount má třída pole jen pro čtení minimálního zůstatku, je poslední změnou změna v metodě na pevný kód minimumBalance0MakeWithdrawal:


if (Balance - amount < _minimumBalance)

Po rozšíření BankAccount třídy můžete upravit LineOfCreditAccount konstruktor tak, aby volal nový základní konstruktor, jak je znázorněno v následujícím kódu:


public LineOfCreditAccount(string name, decimal initialBalance, decimal creditLimit) : base(name, initialBalance, -creditLimit)
{
}

Všimněte si, že LineOfCreditAccount konstruktor změní znaménko parametru creditLimit tak, aby odpovídalo významu parametru minimumBalance .

Týden 5

Různá pravidla kontokorentu

Poslední funkce, kterou chcete přidat, umožňuje LineOfCreditAccount účtovat poplatek za překročení úvěrového limitu místo odmítnutí transakce.

Jednou z technik je definování virtuální funkce, ve které implementujete požadované chování. Třída BankAccount refaktoruje metodu MakeWithdrawal do dvou metod. Nová metoda provede zadanou akci, když výběr vezme zůstatek pod minimum. Existující MakeWithdrawal metoda má následující kód:


public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    }
    if (Balance - amount < _minimumBalance)
    {
        throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    }
    var withdrawal = new Transaction(-amount, date, note);
    _allTransactions.Add(withdrawal);
}

Nahraďte ho následujícím kódem:


public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    }
    Transaction? overdraftTransaction = CheckWithdrawalLimit(Balance - amount < _minimumBalance);
    Transaction? withdrawal = new(-amount, date, note);
    _allTransactions.Add(withdrawal);
    if (overdraftTransaction != null)
        _allTransactions.Add(overdraftTransaction);
}protected virtual Transaction? CheckWithdrawalLimit(bool isOverdrawn)
{
    if (isOverdrawn)
    {
        throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    }
    else
    {
        return default;
    }
}

Přidaná metoda je protected, což znamená, že ji lze volat pouze z odvozených tříd. Tato deklarace brání ostatním klientům v volání metody. Je to také virtual proto, aby odvozené třídy mohly změnit chování. Návratový typ je Transaction?. Poznámka ? označuje, že metoda může vrátit null. Přidejte do pole následující implementaci, která vyúčtuje LineOfCreditAccount poplatek při překročení limitu výběru:



    isOverdrawn
    ? new Transaction(-20, DateTime.Now, "Apply overdraft fee")
    : default;
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">protected override Transaction? CheckWithdrawalLimit(bool isOverdrawn) =>
    isOverdrawn
    ? new Transaction(-20, DateTime.Now, "Apply overdraft fee")
    : default;

Přepsání vrátí transakci s poplatky, když je účet překreslen. Pokud výběr nepřesáhl limit, metoda vrátí null transakci. To znamená, že se nic neplatí. Otestujte tyto změny přidáním následujícího kódu do metody Main ve Program třídě:


var lineOfCredit = new LineOfCreditAccount("line of credit", 0, 2000);
// How much is too much to borrow?
lineOfCredit.MakeWithdrawal(1000m, DateTime.Now, "Take out monthly advance");
lineOfCredit.MakeDeposit(50m, DateTime.Now, "Pay back small amount");
lineOfCredit.MakeWithdrawal(5000m, DateTime.Now, "Emergency funds for repairs");
lineOfCredit.MakeDeposit(150m, DateTime.Now, "Partial restoration on repairs");
lineOfCredit.PerformMonthEndTransactions();
Console.WriteLine(lineOfCredit.GetAccountHistory());

Spusťte program a zkontrolujte výsledky.

Souhrn

Pokud jste se zasekli, můžete se podívat na zdroj tohoto kurzu v našem úložišti GitHub.

Tento kurz ukázal mnoho technik používaných při programování Object-Oriented:

  • Abstrakci jste použili při definování tříd pro každý z různých typů účtů. Tyto třídy popisují chování tohoto typu účtu.
  • Při uchovávání mnoha podrobností private v každé třídě jste použili encapsulation.
  • Použili jste dědičnost , když jste k uložení kódu využili implementaci již vytvořenou BankAccount ve třídě.
  • Polymorfismus jste použili při vytváření virtual metod, které by odvozené třídy mohly přepsat, aby se vytvořilo specifické chování pro daný typ účtu.

Týden 6

Scénáře pro porovnávání vzorů

Moderní vývoj často zahrnuje integraci dat z více zdrojů a prezentaci informací a přehledů z nich v jedné soudržné aplikaci. Vy ani váš tým nebudete mít kontrolu ani přístup ke všem typům, které představují příchozí data.

Klasický objektově orientovaný návrh by volal vytvoření typů v aplikaci, které představují každý datový typ z těchto více zdrojů dat. Aplikace pak bude pracovat s těmito novými typy, vytvářet hierarchie dědičnosti, vytvářet virtuální metody a implementovat abstrakce. Tyto techniky fungují a někdy jsou to nejlepší nástroje. Jindy můžete psát méně kódu. Srozumitelnější kód můžete napsat pomocí technik, které oddělují data od operací, které s nimi pracují.

V tomto kurzu vytvoříte a prozkoumáte aplikaci, která přebírá příchozí data z několika externích zdrojů pro jeden scénář. Uvidíte, jak porovnávání vzorů poskytuje efektivní způsob, jak tato data využívat a zpracovávat způsoby, které nebyly součástí původního systému.

Představte si hlavní metropolitní oblast, která ke správě provozu využívá placené poplatky a ceny ve špičce. Napíšete aplikaci, která vypočítá mýtné pro vozidlo na základě jeho typu. Pozdější vylepšení zahrnují ceny na základě počtu cestujících ve vozidle. Další vylepšení přidávají ceny na základě času a dne v týdnu.

Z tohoto stručného popisu jste možná rychle načrtli hierarchii objektů pro modelování tohoto systému. Vaše data však pocházejí z různých zdrojů, jako jsou jiné systémy správy registrací vozidel. Tyto systémy poskytují různé třídy pro modelování těchto dat a vy nemáte jediný objektový model, který můžete použít. V tomto kurzu použijete tyto zjednodušené třídy k modelování dat vozidla z těchto externích systémů, jak je znázorněno v následujícím kódu:


namespace ConsumerVehicleRegistration
{
    public class Car
    {
        public int Passengers { get; set; }
    }
}namespace CommercialRegistration
{
    public class DeliveryTruck
    {
        public int GrossWeightClass { get; set; }
    }
}namespace LiveryRegistration
{
    public class Taxi
    {
        public int Fares { get; set; }
    }    public class Bus
    {
        public int Capacity { get; set; }
        public int Riders { get; set; }
    }
}

Počáteční kód si můžete stáhnout z úložiště Dotnet/samples na GitHubu. Vidíte, že třídy vozidel pocházejí z různých systémů a jsou v různých oborech názvů. Nelze použít žádnou jinou System.Object společnou základní třídu.

Návrhy porovnávání vzorů

Scénář použitý v tomto kurzu zvýrazňuje druhy problémů, které jsou vhodné k řešení párování vzorů:

  • Objekty, se kterými potřebujete pracovat, nejsou v hierarchii objektů, která odpovídá vašim cílům. Možná pracujete s třídami, které jsou součástí nesouvisejících systémů.
  • Funkce, které přidáváte, nejsou součástí základní abstrakce pro tyto třídy. Mýto placené vozidlem se mění pro různé typy vozidel, ale není základní funkcí vozidla.

Pokud tvar dat a operace s daty nejsou popsány společně, funkce porovnávání vzorů v jazyce C# usnadňují práci.

Implementace základních výpočtů mýta

Nejzákladnější výpočet mýta závisí pouze na typu vozidla:

  • Car je $2,00.
  • Taxi je 3,50 USD.
  • Bus je 5,00 USD.
  • DeliveryTruck je $10,00

Vytvořte novou TollCalculator třídu a implementujte porovnávání vzorů pro typ vozidla, abyste získali částku placené. Následující kód ukazuje počáteční implementaci TollCalculator.



        vehicle switch
    {
        Car c           => 2.00m,
        Taxi t          => 3.50m,
        Bus b           => 5.00m,
        DeliveryTruck t => 10.00m,
        { }             => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null            => throw new ArgumentNullException(nameof(vehicle))
    };
}
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;namespace Calculators;public class TollCalculator
{
    public decimal CalculateToll(object vehicle) =>
        vehicle switch
    {
        Car c           => 2.00m,
        Taxi t          => 3.50m,
        Bus b           => 5.00m,
        DeliveryTruck t => 10.00m,
        { }             => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null            => throw new ArgumentNullException(nameof(vehicle))
    };
}

Předchozí kód používá switch výraz (ne stejný jako switch příkaz), který testuje vzor deklaraceVýraz switch začíná proměnnou v vehicle předchozím kódu následovanou klíčovým slovemswitch. Dále přichází všechna spínací ramena uvnitř složených závorek. Výraz switch provede další vylepšení syntaxe, která příkaz obklopuje switch . Klíčové case slovo je vynecháno a výsledkem každého armu je výraz. Poslední dvě ramena ukazují novou funkci jazyka. Případ { } odpovídá jakémukoli objektu, který není null, který se neshodoval s dřívějším armem. Toto rameno zachytí všechny nesprávné typy předané této metodě. Případ { } musí odpovídat případům pro každý typ vozidla. Pokud by se pořadí obrátilo, { } případ by měl přednost. Nakonec konstantní vzor zjistí, null kdy null je předán této metodě. Vzor null může být poslední, protože ostatní vzory odpovídají pouze objektu správného typu, který není null.

Tento kód můžete otestovat pomocí následujícího kódu v nástroji Program.cs:


using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;using toll_calculator;var tollCalc = new TollCalculator();var car = new Car();
var taxi = new Taxi();
var bus = new Bus();
var truck = new DeliveryTruck();Console.WriteLine($"The toll for a car is {tollCalc.CalculateToll(car)}");
Console.WriteLine($"The toll for a taxi is {tollCalc.CalculateToll(taxi)}");
Console.WriteLine($"The toll for a bus is {tollCalc.CalculateToll(bus)}");
Console.WriteLine($"The toll for a truck is {tollCalc.CalculateToll(truck)}");try
{
    tollCalc.CalculateToll("this will fail");
}
catch (ArgumentException e)
{
    Console.WriteLine("Caught an argument exception when using the wrong type");
}
try
{
    tollCalc.CalculateToll(null!);
}
catch (ArgumentNullException e)
{
    Console.WriteLine("Caught an argument exception when using null");
}

Tento kód je součástí úvodního projektu, ale je zakomentován. Odeberte komentáře a můžete otestovat, co jste napsali.

Začínáte vidět, jak vám vzory můžou pomoct vytvořit algoritmy, ve kterých jsou kód a data oddělená. Výraz switch testuje typ a na základě výsledků vytvoří různé hodnoty. To je jen začátek.

Přidání cen obsazenosti

Mýtný úřad chce nabádnout vozidla k maximální kapacitě. Rozhodli se účtovat vyšší poplatky, pokud mají vozidla méně cestujících, a podporovat kompletní vozidla tím, že nabízí nižší ceny:

  • Auta a taxi bez cestujících platí navíc 0,50 USD.
  • Auta a taxi se dvěma cestujícími získají slevu 0,50 USD.
  • Auta a taxíky se třemi nebo více cestujícími získají slevu 1,00 USD.
  • Autobusy, které jsou méně než 50% plné, platí navíc 2,00 USD.
  • Autobusy, které jsou více než 90% plné, dostanou slevu 1,00 USD.

Tato pravidla je možné implementovat pomocí vzoru vlastnosti ve stejném výrazu přepínače. Vzor vlastnosti porovnává hodnotu vlastnosti s konstantní hodnotou. Vzor vlastnosti zkoumá vlastnosti objektu po určení typu. Jedno velké písmeno rozbalí Car na čtyři různé případy:


 2.00m + 0.50m,
    Car {Passengers: 1} => 2.0m,
    Car {Passengers: 2} => 2.0m - 0.50m,
    Car                 => 2.00m - 1.0m,    // ...
};
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">vehicle switch
{
    Car {Passengers: 0} => 2.00m + 0.50m,
    Car {Passengers: 1} => 2.0m,
    Car {Passengers: 2} => 2.0m - 0.50m,
    Car                 => 2.00m - 1.0m,    // ...
};

První tři případy testují typ jako Cara pak zkontrolujte hodnotu Passengers vlastnosti. Pokud se oba shodují, tento výraz se vyhodnotí a vrátí.

Podobným způsobem byste také rozšířili případy taxislužby:


 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,    // ...
};
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">vehicle switch
{
    // ...    Taxi {Fares: 0}  => 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,    // ...
};

Dále implementujte pravidla obsazenosti rozšířením případů pro autobusy, jak je znázorněno v následujícím příkladu:


 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,    // ...
};
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">vehicle switch
{
    // ...    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,    // ...
};

Mýtný úřad se nezabývá počtem cestujících v nákladních vozidlech. Místo toho upraví výši mýtného na základě hmotnostní třídy nákladních vozů následujícím způsobem:

  • Nákladní vozy nad 5000 liber se účtují za příplatek 5,00 USD.
  • Lehké nákladní vozy do 3000 liber mají slevu 2,00 USD.

Toto pravidlo se implementuje s následujícím kódem:


 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,
};
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">vehicle switch
{
    // ...    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,
};

Předchozí kód zobrazuje klauzuli when spínacího ramene. Klauzuli when použijete k testování jiných podmínek než rovnosti u vlastnosti. Po dokončení budete mít metodu, která vypadá podobně jako následující kód:


 2.00m + 0.50m,
    Car {Passengers: 1}        => 2.0m,
    Car {Passengers: 2}        => 2.0m - 0.50m,
    Car                        => 2.00m - 1.0m,    Taxi {Fares: 0}  => 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,    { }     => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
    null    => throw new ArgumentNullException(nameof(vehicle))
};
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">vehicle switch
{
    Car {Passengers: 0}        => 2.00m + 0.50m,
    Car {Passengers: 1}        => 2.0m,
    Car {Passengers: 2}        => 2.0m - 0.50m,
    Car                        => 2.00m - 1.0m,    Taxi {Fares: 0}  => 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,    { }     => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
    null    => throw new ArgumentNullException(nameof(vehicle))
};

Mnoho z těchto spínacích ramen je příkladem rekurzivních vzorůCar { Passengers: 1} Například zobrazuje konstantní vzor uvnitř vzoru vlastnosti.

Pomocí vnořených přepínačů můžete tento kód zmenšit. Taxi Oba Car mají v předchozích příkladech čtyři různá ramena. V obou případech můžete vytvořit vzor deklarace, který je součástí konstantního vzoru. Tato technika je znázorněna v následujícím kódu:



    vehicle switch
    {
        Car c => c.Passengers switch
        {
            0 => 2.00m + 0.5m,
            1 => 2.0m,
            2 => 2.0m - 0.5m,
            _ => 2.00m - 1.0m
        },        Taxi t => t.Fares switch
        {
            0 => 3.50m + 1.00m,
            1 => 3.50m,
            2 => 3.50m - 0.50m,
            _ => 3.50m - 1.00m
        },        Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
        Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
        Bus b => 5.00m,        DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
        DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
        DeliveryTruck t => 10.00m,        { }  => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null => throw new ArgumentNullException(nameof(vehicle))
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">public decimal CalculateToll(object vehicle) =>
    vehicle switch
    {
        Car c => c.Passengers switch
        {
            0 => 2.00m + 0.5m,
            1 => 2.0m,
            2 => 2.0m - 0.5m,
            _ => 2.00m - 1.0m
        },        Taxi t => t.Fares switch
        {
            0 => 3.50m + 1.00m,
            1 => 3.50m,
            2 => 3.50m - 0.50m,
            _ => 3.50m - 1.00m
        },        Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
        Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
        Bus b => 5.00m,        DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
        DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
        DeliveryTruck t => 10.00m,        { }  => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null => throw new ArgumentNullException(nameof(vehicle))
    };

V předchozí ukázce použití rekurzivního výrazu znamená, že neopakujete Car ramena a Taxi obsahující podřízené paže, které testují hodnotu vlastnosti. Tato technika se nepoužívá pro ramena Bus a DeliveryTruck , protože tyto ramena testují rozsahy pro vlastnost, nikoli diskrétní hodnoty.

Týden 7

Přidání cen ve špičce

U konečné funkce chce mýtný úřad přidat časově citlivé ceny ve špičce. V ranních a večerních špičkách se placené poplatky zdvojnásobí. Toto pravidlo má vliv pouze na provoz v jednom směru: příchozí do města ráno a odchozí ve večerní špičce. V jiných časech během pracovního dne se placené poplatky zvyšují o 50 %. Pozdě v noci a brzy ráno je placená daň snížena o 25 %. O víkendu je to normální sazba bez ohledu na čas. K vyjádření tohoto problému můžete použít řadu if příkazů a else pomocí následujícího kódu:


public decimal PeakTimePremiumIfElse(DateTime timeOfToll, bool inbound)
{
    if ((timeOfToll.DayOfWeek == DayOfWeek.Saturday) ||
        (timeOfToll.DayOfWeek == DayOfWeek.Sunday))
    {
        return 1.0m;
    }
    else
    {
        int hour = timeOfToll.Hour;
        if (hour < 6)
        {
            return 0.75m;
        }
        else if (hour < 10)
        {
            if (inbound)
            {
                return 2.0m;
            }
            else
            {
                return 1.0m;
            }
        }
        else if (hour < 16)
        {
            return 1.5m;
        }
        else if (hour < 20)
        {
            if (inbound)
            {
                return 1.0m;
            }
            else
            {
                return 2.0m;
            }
        }
        else // Overnight
        {
            return 0.75m;
        }
    }
}

Předchozí kód funguje správně, ale není čitelný. Abyste mohli o kódu uvažovat, musíte projít všechny vstupní případy a vnořené if příkazy. Místo toho pro tuto funkci použijete porovnávání vzorů, ale integrujete ji s jinými technikami. Mohli byste vytvořit jeden výraz shody se vzorem, který by zohlednil všechny kombinace směru, dne v týdnu a času. Výsledkem by byl složitý výraz. Bylo by těžké ho číst a těžko pochopit. To ztěžuje zajištění správnosti. Místo toho zkombinujte tyto metody a vytvořte řazenou kolekci hodnot, která výstižně popisuje všechny tyto stavy. Pak použijte porovnávání vzorů k výpočtu multiplikátoru pro placenou linku. Řazená kolekce členů obsahuje tři samostatné podmínky:

  • Den je buď pracovní den, nebo víkend.
  • Časové pásmo, kdy se vybírá placená platba.
  • Směr je do města nebo mimo město

Následující tabulka uvádí kombinace vstupních hodnot a násobitele cen ve špičce:

DateTime strukturu pro čas, kdy byla placená platba vybrána. Sestavte členské metody, které vytvářejí proměnné z předchozí tabulky. Následující funkce používá výraz switch odpovídající vzor k vyjádření toho, jestli představuje DateTime víkend nebo den v týdnu:



    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Monday    => true,
        DayOfWeek.Tuesday   => true,
        DayOfWeek.Wednesday => true,
        DayOfWeek.Thursday  => true,
        DayOfWeek.Friday    => true,
        DayOfWeek.Saturday  => false,
        DayOfWeek.Sunday    => false
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private static bool IsWeekDay(DateTime timeOfToll) =>
    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Monday    => true,
        DayOfWeek.Tuesday   => true,
        DayOfWeek.Wednesday => true,
        DayOfWeek.Thursday  => true,
        DayOfWeek.Friday    => true,
        DayOfWeek.Saturday  => false,
        DayOfWeek.Sunday    => false
    };

Tato metoda je správná, ale je opakovaná. Můžete ho zjednodušit, jak je znázorněno v následujícím kódu:



    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Saturday => false,
        DayOfWeek.Sunday => false,
        _ => true
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private static bool IsWeekDay(DateTime timeOfToll) =>
    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Saturday => false,
        DayOfWeek.Sunday => false,
        _ => true
    };

Dále přidejte podobnou funkci, která čas kategorizuje do bloků:



    timeOfToll.Hour switch
    {
        < 6 or > 19 => TimeBand.Overnight,
        < 10 => TimeBand.MorningRush,
        < 16 => TimeBand.Daytime,
        _ => TimeBand.EveningRush,
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">private enum TimeBand
{
    MorningRush,
    Daytime,
    EveningRush,
    Overnight
}private static TimeBand GetTimeBand(DateTime timeOfToll) =>
    timeOfToll.Hour switch
    {
        < 6 or > 19 => TimeBand.Overnight,
        < 10 => TimeBand.MorningRush,
        < 16 => TimeBand.Daytime,
        _ => TimeBand.EveningRush,
    };

Přidáte privátní enum pro převod každého časového rozsahu na diskrétní hodnotu. GetTimeBand Pak metoda používá relační vzory a konjunktivní or vzory, které jsou přidané v jazyce C# 9.0. Relační vzor umožňuje otestovat číselnou hodnotu pomocí <><=nebo >=. Vzor or testuje, jestli výraz odpovídá jednomu nebo více vzorům. Můžete také použít and vzor, který zajistí, aby výraz odpovídal dvěma odlišným not vzorům, a vzor, který otestuje, že výraz neodpovídá vzoru.

Po vytvoření těchto metod můžete k výpočtu cenové úrovně Premium použít jiný switch výraz se vzorem řazené kolekce členů . Mohli byste vytvořit výraz se switch všemi 16 rameny:



    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true) => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime, true) => 1.50m,
        (true, TimeBand.Daytime, false) => 1.50m,
        (true, TimeBand.EveningRush, true) => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight, true) => 0.75m,
        (true, TimeBand.Overnight, false) => 0.75m,
        (false, TimeBand.MorningRush, true) => 1.00m,
        (false, TimeBand.MorningRush, false) => 1.00m,
        (false, TimeBand.Daytime, true) => 1.00m,
        (false, TimeBand.Daytime, false) => 1.00m,
        (false, TimeBand.EveningRush, true) => 1.00m,
        (false, TimeBand.EveningRush, false) => 1.00m,
        (false, TimeBand.Overnight, true) => 1.00m,
        (false, TimeBand.Overnight, false) => 1.00m,
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">public decimal PeakTimePremiumFull(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true) => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime, true) => 1.50m,
        (true, TimeBand.Daytime, false) => 1.50m,
        (true, TimeBand.EveningRush, true) => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight, true) => 0.75m,
        (true, TimeBand.Overnight, false) => 0.75m,
        (false, TimeBand.MorningRush, true) => 1.00m,
        (false, TimeBand.MorningRush, false) => 1.00m,
        (false, TimeBand.Daytime, true) => 1.00m,
        (false, TimeBand.Daytime, false) => 1.00m,
        (false, TimeBand.EveningRush, true) => 1.00m,
        (false, TimeBand.EveningRush, false) => 1.00m,
        (false, TimeBand.Overnight, true) => 1.00m,
        (false, TimeBand.Overnight, false) => 1.00m,
    };

Výše uvedený kód funguje, ale dá se ho zjednodušit. Všech osm kombinací pro víkend má stejné mýto. Všech osm můžete nahradit následujícím řádkem:


 1.0m,
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">(false, _, _) => 1.0m,

Příchozí i odchozí provoz mají stejný násobitel během dne v týdnu i v nočních hodinách. Tato čtyři spínací ramena mohou být nahrazena následujícími dvěma řádky:


 0.75m,
(true, TimeBand.Daytime, _)   => 1.5m,
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">(true, TimeBand.Overnight, _) => 0.75m,
(true, TimeBand.Daytime, _)   => 1.5m,

Kód by měl vypadat jako následující kód po těchto dvou změnách:



    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true)  => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime,     _)     => 1.50m,
        (true, TimeBand.EveningRush, true)  => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight,   _)     => 0.75m,
        (false, _,                   _)     => 1.00m,
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true)  => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime,     _)     => 1.50m,
        (true, TimeBand.EveningRush, true)  => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight,   _)     => 0.75m,
        (false, _,                   _)     => 1.00m,
    };

Nakonec můžete odebrat dvě špičky, které platí běžnou cenu. Jakmile tyto paže vyjmete, můžete nahradit false zahozenou (_) v posledním rameni spínače. Budete mít následující dokončenou metodu:



    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.Overnight, _) => 0.75m,
        (true, TimeBand.Daytime, _) => 1.5m,
        (true, TimeBand.MorningRush, true) => 2.0m,
        (true, TimeBand.EveningRush, false) => 2.0m,
        _ => 1.0m,
    };
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.Overnight, _) => 0.75m,
        (true, TimeBand.Daytime, _) => 1.5m,
        (true, TimeBand.MorningRush, true) => 2.0m,
        (true, TimeBand.EveningRush, false) => 2.0m,
        _ => 1.0m,
    };

Tento příklad zvýrazňuje jednu z výhod porovnávání vzorů: větve vzorů se vyhodnocují v pořadí. Pokud je přeskupíte tak, aby starší větev zpracovávala některý z pozdějších případů, kompilátor vás upozorní na nedostupný kód. Tato jazyková pravidla usnadnila předchozí zjednodušení s jistotou, že se kód nezměnil.

Porovnávání vzorů dělá některé typy kódu čitelnější a nabízí alternativu k objektům orientovaným technikám, když nemůžete přidat kód do tříd. Cloud způsobuje, že data a funkce se od sebe oddělují. Tvar dat a operace s ním nejsou nutně popsány společně. V tomto kurzu jste využili existující data úplně jinak než jejich původní funkce. Porovnávání vzorů vám umožnilo psát funkce, které tyto typy přetěžují, i když jste je nemohli rozšířit.

Další kroky

Hotový kód si můžete stáhnout z úložiště githubu dotnet/samples . Prozkoumejte vlastní vzory a přidejte tuto techniku do běžných aktivit kódování. Když se tyto techniky naučíte, získáte další způsob, jak přistupovat k problémům a vytvářet nové funkce.

undefined

Existuje 16 různých kombinací těchto tří proměnných. Kombinací některých podmínek zjednodušíte konečný výraz switch.

Systém, který vybírá placené poplatky, používá 

Týden 8

Zpracování vyjímky

Účelem bloku try-catch je zachytit a zpracovat výjimku vygenerovanou pracovním kódem. Některé výjimky se dají zpracovat v catch bloku a problém se vyřeší, aniž by se výjimka znovu vygenerovala. Častěji se ale jediná věc, kterou můžete udělat, je ujistit se, že je vyvolána příslušná výjimka.

Příklad

V tomto příkladu není nejvhodnější výjimkou: ArgumentOutOfRangeException dává větší smysl pro metodu, IndexOutOfRangeException protože chybu způsobuje index argument předaný volajícím.


static int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e)  // CS0168
    {
        Console.WriteLine(e.Message);
        // Set IndexOutOfRangeException to the new exception's InnerException.
        throw new ArgumentOutOfRangeException("index parameter is out of range.", e);
    }
}

Komentáře

Kód, který způsobuje výjimku, je uzavřen v try bloku . Okamžitě catch za něj se přidá příkaz pro zpracování IndexOutOfRangeException, pokud k němu dojde. Blok catch zpracovává IndexOutOfRangeException a místo toho vyvolá vhodnější ArgumentOutOfRangeException . Pokud chcete volajícímu poskytnout co nejvíce informací, zvažte zadání původní výjimky jako InnerException nové výjimky. Vzhledem k tomu, InnerException že vlastnost je jen pro čtení, musíte ji přiřadit v konstruktoru nové výjimky.

Týden 9

Možnosti použití LINQ to SQL

LINQ to SQL podporuje všechny klíčové funkce, které byste jako vývojáři SQL očekávali. Můžete se dotazovat na informace a vkládat, aktualizovat a odstraňovat informace z tabulek.

Výběr

Výběr (projekce) se provádí tak, že jednoduše napíšete dotaz LINQ ve vlastním programovacím jazyce a pak ho spustíte, aby se načetly výsledky. LINQ to SQL sama překládá všechny potřebné operace do potřebných operací SQL, které znáte. Další informace najdete v tématu LINQ to SQL.

V následujícím příkladu se načtou názvy společností zákazníků z Londýna a zobrazí se v okně konzoly.


// Northwnd inherits from System.Data.Linq.DataContext.
Northwnd nw = new Northwnd(@"northwnd.mdf");
// or, if you are not using SQL Server Express
// Northwnd nw = new Northwnd("Database=Northwind;Server=server_name;Integrated Security=SSPI");var companyNameQuery =
    from cust in nw.Customers
    where cust.City == "London"
    select cust.CompanyName;foreach (var customer in companyNameQuery)
{
    Console.WriteLine(customer);
}

Vložení

Pokud chcete spustit SQL Insert, stačí přidat objekty do objektového modelu, který jste vytvořili, a volat SubmitChanges na DataContext.

V následujícím příkladu se do Customers tabulky přidá nový zákazník a informace o zákazníkovi pomocí InsertOnSubmitpříkazu .


// Northwnd inherits from System.Data.Linq.DataContext.
Northwnd nw = new Northwnd(@"northwnd.mdf");Customer cust = new Customer();
cust.CompanyName = "SomeCompany";
cust.City = "London";
cust.CustomerID = "98128";
cust.PostalCode = "55555";
cust.Phone = "555-555-5555";
nw.Customers.InsertOnSubmit(cust);// At this point, the new Customer object is added in the object model.
// In LINQ to SQL, the change is not sent to the database until
// SubmitChanges is called.
nw.SubmitChanges();

Aktualizace

Do Update položky databáze nejprve načtěte položku a upravte ji přímo v objektovém modelu. Po úpravě objektu proveďte aktualizaci databáze voláním SubmitChangesDataContext příkazu .

V následujícím příkladu se načtou všichni zákazníci z Londýna. Pak se název města změní z "Londýn" na "Londýn - metro". Nakonec se zavolá, SubmitChanges aby se změny odeslaly do databáze.


Northwnd nw = new Northwnd(@"northwnd.mdf");var cityNameQuery =
    from cust in nw.Customers
    where cust.City.Contains("London")
    select cust;foreach (var customer in cityNameQuery)
{
    if (customer.City == "London")
    {
        customer.City = "London - Metro";
    }
}
nw.SubmitChanges();

odstraňování

Delete položce odeberte položku z kolekce, do které patří, a pak voláním na SubmitChangesDataContext položku potvrďte změnu.

si téma Postupy: Odstranění řádků z databáze.

V následujícím příkladu se z databáze načte zákazník, který ho 98128 máCustomerID. Po potvrzení, že byl načten řádek zákazníka, DeleteOnSubmit je volána, aby se tento objekt odebral z kolekce. SubmitChanges Nakonec je volána k předání odstranění do databáze.


 0)
{
    nw.Customers.DeleteOnSubmit(deleteIndivCust.First());
    nw.SubmitChanges();
}
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">Northwnd nw = new Northwnd(@"northwnd.mdf");
var deleteIndivCust =
    from cust in nw.Customers
    where cust.CustomerID == "98128"
    select cust;if (deleteIndivCust.Count() > 0)
{
    nw.Customers.DeleteOnSubmit(deleteIndivCust.First());
    nw.SubmitChanges();
}

Týden 10

LINQ přehled

Pokud chcete implementovat aplikaci LINQ to SQL, postupujte podle kroků popsaných dále v tomto tématu. Všimněte si, že mnoho kroků je nepovinných. Je velmi možné, že můžete objektový model použít ve výchozím stavu.

Pokud chcete začít opravdu rychle, použijte Návrhář relací objektů k vytvoření objektového modelu a začněte kódovat dotazy.

Vytvoření objektového modelu

Prvním krokem je vytvoření objektového modelu z metadat existující relační databáze. Objektový model představuje databázi podle programovacího jazyka vývojáře. Další informace najdete v tématu Objektový model LINQ to SQL.

1. Vyberte nástroj pro vytvoření modelu.

Pro vytvoření modelu jsou k dispozici tři nástroje.

  • Návrhář relací objektů

    Tento návrhář poskytuje bohaté uživatelské rozhraní pro vytvoření objektového modelu z existující databáze. Tento nástroj je součástí integrovaného vývojového prostředí sady Visual Studio a je nejvhodnější pro malé nebo střední databáze.

  • Nástroj pro generování kódu SQLMetal

    Tento nástroj příkazového řádku poskytuje trochu jinou sadu možností než Designer O/R. Modelování velkých databází se nejlépe provádí pomocí tohoto nástroje. Další informace najdete v tématu SqlMetal.exe (nástroj pro generování kódu).

  • Editor kódu

    Vlastní kód můžete napsat buď pomocí editoru editoru visual studio code, nebo jiného editoru. Nedoporučujeme tento přístup, který může být náchylný k chybám, pokud máte existující databázi a můžete použít Designer O/R nebo nástroj SQLMetal. Editor kódu ale může být užitečný pro zpřesnění nebo úpravu kódu, který jste už vygenerovali pomocí jiných nástrojů. Další informace najdete v tématu Postupy: Přizpůsobení tříd entit pomocí editoru kódu.

2. Vyberte typ kódu, který chcete vygenerovat.

  • Soubor zdrojového kódu jazyka C# nebo Visual Basic pro mapování na základě atributů.

    Potom tento soubor kódu zahrnete do projektu sady Visual Studio. Další informace najdete v tématu Mapování na základě atributů.

  • Soubor XML pro externí mapování.

    Pomocí tohoto přístupu můžete zachovat metadata mapování mimo kód aplikace. Další informace najdete v tématu Externí mapování.

  • Soubor DBML, který můžete upravit před vygenerováním konečného souboru kódu.

    Jedná se o pokročilou funkci.

3. Upřesněte soubor kódu tak, aby odrážel potřeby vaší aplikace.

K tomuto účelu můžete použít buď Designer O/R, nebo editor kódu.

Použití objektového modelu

Následující obrázek znázorňuje vztah mezi vývojářem a daty ve dvouvrstvém scénáři. Další scénáře najdete v tématu N-vrstvé a vzdálené aplikace s LINQ to SQL.

Týden 11

Zobrazení kódu SQL

Pomocí vlastnosti můžete zobrazit kód SQL vygenerovaný pro dotazy a zpracování Log změn. Tento přístup může být užitečný pro pochopení LINQ to SQL funkcí a ladění specifických problémů.

Příklad

Následující příklad používá Log vlastnost k zobrazení kódu SQL v okně konzoly před spuštěním kódu. Tuto vlastnost můžete použít s příkazy dotazu, vložení, aktualizace a odstranění.

Řádky z okna konzoly jsou to, co vidíte při spuštění následujícího kódu jazyka Visual Basic nebo C#.

Konzola
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactT  
itle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Coun  
try], [t0].[Phone], [t0].[Fax]  
FROM [dbo].[Customers] AS [t0]  
WHERE [t0].[City] = @p0  
-- @p0: Input String (Size = 6; Prec = 0; Scale = 0) [London]  
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20810.0  
Konzola
AROUT  
BSBEV  
CONSH  
EASTC  
NORTS  
SEVES  

 custQuery =
    from cust in db.Customers
    where cust.City == "London"
    select cust;foreach(Customer custObj in custQuery)
{
    Console.WriteLine(custObj.CustomerID);
}
" style="box-sizing: inherit; outline-color: inherit; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 1em; direction: ltr; border: 0px; padding: 0px; line-height: 1.3571; display: block; position: relative;">db.Log = Console.Out;
IQueryable<Customer> custQuery =
    from cust in db.Customers
    where cust.City == "London"
    select cust;foreach(Customer custObj in custQuery)
{
    Console.WriteLine(custObj.CustomerID);
}

Týden 12

Opakování znalostí, zápočtový test.

Týden 13

Odevzdávání zápočtových projektů.