Cvičení – refaktoring a vylepšení oddílů kódu pomocí nástrojů GitHub Copilot

Dokončeno

GitHub Copilot vám může pomoct s aktualizací kódu tím, že navrhne změny, které zlepšují kvalitu, spolehlivost, výkon a zabezpečení kódu.

V tomto cvičení použijete GitHub Copilot k refaktoringu a vylepšení následujících částí kódu:

  • Refaktoring EnumHelper třídy používat slovníky místo reflexe. Použití slovníků zlepšuje výkon snížením režie reflexe. Eliminování reflexe také zlepšuje čitelnost kódu, udržovatelnost a zabezpečení.

  • Refaktorujete metody přístupu k datům tak, aby místo smyčky foreach používaly LINQ (Language Integrated Query). Použití LINQ poskytuje stručnější a čitelnější způsob dotazování kolekcí, databází a dokumentů XML. Použití LINQ může zlepšit čitelnost kódu, udržovatelnost a výkon.

Refaktoring třídy EnumHelper pomocí GitHub Copilotu

Reflexe je výkonná funkce, která umožňuje kontrolovat a manipulovat s objekty za běhu. Reflexe však může být pomalá a k reflexi by se měla zvážit potenciální bezpečnostní rizika.

Existující EnumHelper třída používá reflexi k načtení atributu popisu výčtu hodnoty. Refaktoring EnumHelper třídy použít slovníky místo reflexe. Použití slovníků může zlepšit výkon a eliminovat případné obavy zabezpečení spojené s použitím reflexe.

V tomto cvičení použijete GitHub Copilot, který vám pomůže refaktorovat třídu EnumHelper.

K dokončení této části cvičení použijte následující kroky:

  1. V zobrazení Průzkumník řešení otevřete soubor EnumHelper.cs.

    using System.ComponentModel;
    using System.Reflection;
    
    namespace Library.ApplicationCore.Enums;
    
    public static class EnumHelper
    {
        public static string GetDescription(Enum value)
        {
            if (value == null)
                return string.Empty;
    
            FieldInfo fieldInfo = value.GetType().GetField(value.ToString())!;
    
            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
    
            if (attributes != null && attributes.Length > 0)
            {
                return attributes[0].Description;
            }
            else
            {
                return value.ToString();
            }
        }
    }
    
  2. Otevřete zobrazení Chat a pak do kontextu chatu přidejte následující soubory: EnumHelper.cs, LoanExtensionStatus.cs, LoanReturnStatus.cs, MembershipRenewalStatus.cs.

  3. Zadejte následující výzvu:

    @workspace I want to refactor the `EnumHelper` class using dictionaries rather than reflection to get enum description attributes. I want a separate dictionary for each enum. The enum values are in the `LoanExtensionStatus.cs`, `LoanReturnStatus.cs`, and `MembershipRenewalStatus.cs` files. Explain how to update the EnumHelper class to use dictionaries and provide the updated code.
    

    Tato výzva požádá GitHub Copilot, aby poskytl vysvětlení, jak aktualizovat třídu EnumHelper tak, aby místo reflexe používal slovníky. Také žádá o aktualizovaný kód, který používá slovníky pro každou hodnotu výčtu.

  4. Projděte si vysvětlení, které poskytuje GitHub Copilot.

    Vysvětlení by mělo být podobné následujícímu popisu:

    To refactor the `EnumHelper` class to use dictionaries for each enum, you need to create a dictionary for each enum type that maps the enum values to their descriptions. This will eliminate the need for reflection at runtime.
    
    Here's how you can update the `EnumHelper` class:
    
    1. Create dictionaries for each enum type.
    2. Populate these dictionaries with the enum values and their corresponding descriptions.
    3. Update the `GetDescription` method to use these dictionaries.
    
    Below is the updated code for the EnumHelper class:
    
    
    using System.ComponentModel;
    using System.Collections.Generic;
    
    namespace Library.ApplicationCore.Enums
    {
        public static class EnumHelper
        {
            private static readonly Dictionary<MembershipRenewalStatus, string> MembershipRenewalStatusDescriptions = new()
            {
                { MembershipRenewalStatus.Success, "Membership renewal was successful." },
                { MembershipRenewalStatus.PatronNotFound, "Patron not found." },
                { MembershipRenewalStatus.TooEarlyToRenew, "It is too early to renew the membership." },
                { MembershipRenewalStatus.LoanNotReturned, "Cannot renew membership due to an outstanding loan." },
                { MembershipRenewalStatus.Error, "Cannot renew membership due to an error." }
            };
    
            private static readonly Dictionary<LoanReturnStatus, string> LoanReturnStatusDescriptions = new()
            {
                { LoanReturnStatus.Success, "Book was successfully returned." },
                { LoanReturnStatus.LoanNotFound, "Loan not found." },
                { LoanReturnStatus.AlreadyReturned, "Cannot return book as the book is already returned." },
                { LoanReturnStatus.Error, "Cannot return book due to an error." }
            };
    
            private static readonly Dictionary<LoanExtensionStatus, string> LoanExtensionStatusDescriptions = new()
            {
                { LoanExtensionStatus.Success, "Book loan extension was successful." },
                { LoanExtensionStatus.LoanNotFound, "Loan not found." },
                { LoanExtensionStatus.LoanExpired, "Cannot extend book loan as it already has expired. Return the book instead." },
                { LoanExtensionStatus.MembershipExpired, "Cannot extend book loan due to expired patron's membership." },
                { LoanExtensionStatus.LoanReturned, "Cannot extend book loan as the book is already returned." },
                { LoanExtensionStatus.Error, "Cannot extend book loan due to an error." }
            };
    
            public static string GetDescription(Enum value)
            {
                if (value == null)
                    return string.Empty;
    
                return value switch
                {
                    MembershipRenewalStatus status => MembershipRenewalStatusDescriptions[status],
                    LoanReturnStatus status => LoanReturnStatusDescriptions[status],
                    LoanExtensionStatus status => LoanExtensionStatusDescriptions[status],
                    _ => value.ToString()
                };
            }
        }
    }
    
    
    This refactored EnumHelper class uses dictionaries to store the descriptions for each enum type. The GetDescription method now uses pattern matching to determine the type of the enum and retrieves the description from the appropriate dictionary. This approach avoids the use of reflection and improves performance.
    
    

    Poznámka:

    Pokud GitHub Copilot nevyplní slovníky správnými popisy, ujistěte se, že rozšíření GitHub Copilot nevyžaduje restartování. Pokud ano, restartujte rozšíření a zkuste výzvu zopakovat.

  5. Pomocí navrhované EnumHelper třídy GitHub Copilot aktualizujte soubor EnumHelper.cs.

  6. Ujistěte se, že aktualizovaná EnumHelper třída používá hodnoty výčtu LoanExtensionStatus.csze souboru , LoanReturnStatus.csa MembershipRenewalStatus.cs souborů.

    Otevřete všechny soubory výčtu a ověřte správnost hodnot výčtu ve slovníkech. Pokud dojde k nesrovnalostem, aktualizujte slovníky githubu Copilot pro každý výčt jednotlivě. Můžete například použít následující výzvu k výčtu LoanExtensionStatus :

    @workspace Use the description values in LoanExtensionStatus.cs to update the LoanExtensionStatus dictionary in the EnumHelper class. Provide the updated code for the LoanExtensionStatus dictionary in the EnumHelper class.
    

    V případě potřeby použijte stejný přístup pro LoanReturnStatus výčet a MembershipRenewalStatus výčty.

  7. Projděte si metodu za minutu GetDescription .

    public static string GetDescription(Enum value)
    {
        if (value == null)
            return string.Empty;
    
        return value switch
        {
            MembershipRenewalStatus status => MembershipRenewalStatusDescriptions[status],
            LoanReturnStatus status => LoanReturnStatusDescriptions[status],
            LoanExtensionStatus status => LoanExtensionStatusDescriptions[status],
            _ => value.ToString()
        };
    }
    

    Tento kód používá porovnávání vzorů k určení typu výčtu a načtení popisu z příslušného slovníku. Příkaz switch zkontroluje typ výčtu value a vrátí odpovídající popis ze slovníku. Pokud není hodnota výčtu nalezena ve slovníku, metoda vrátí hodnotu výčtu jako řetězec.

    Pokud se zeptáte GitHub Copilotu, aby refaktoroval tento kód a eliminoval výrazy lambda, bude čitelnější:

    public static string GetDescription(Enum value)
    {
        if (value == null)
            return string.Empty;
    
        switch (value)
        {
            case MembershipRenewalStatus status:
                return MembershipRenewalStatusDescriptions[status];
            case LoanReturnStatus status:
                return LoanReturnStatusDescriptions[status];
            case LoanExtensionStatus status:
                return LoanExtensionStatusDescriptions[status];
            default:
                return value.ToString();
        }
    }
    
  8. Sestavte řešení, abyste zajistili, že nedojde k žádným chybám.

    Zobrazí se upozornění. Prozatím je můžete ignorovat.

Aktualizace metod přístupu k datům tak, aby používaly LINQ

LINQ (Language Integrated Query) je výkonná funkce jazyka C#, která umožňuje dotazovat se na kolekce, databáze a dokumenty XML jednotným způsobem. LINQ poskytuje stručnější a čitelnější způsob dotazování dat v porovnání s tradičními smyčkami foreach.

Tato část cvičení obsahuje následující úlohy:

  • Refaktoring metod v JsonData.cs pro použití LINQ.
  • Refaktoring metod v JsonLoanRepository.cs pro použití LINQ.
  • Refaktoring metod v JsonPatronRepository.cs pro použití LINQ.

Refaktoring metod v JsonData.cs pro použití LINQ

Třída JsonData obsahuje následující metody přístupu k datům: GetPopulatedPatron, GetPopulatedLoan, GetPopulatedBookItem, GetPopulatedBook. Tyto metody používají smyčky foreach k iteraci nad kolekcemi a naplnění objektů. Tyto metody můžete refaktorovat tak, aby používaly LINQ ke zlepšení čitelnosti a udržovatelnosti kódu.

K dokončení této části cvičení použijte následující kroky:

  1. Otevřete soubor JsonData.cs.

  2. Vyberte metodu GetPopulatedPatron.

    Metoda GetPopulatedPatron je navržena tak, aby vytvořila plně naplněný Patron objekt. Zkopíruje základní vlastnosti Patron kolekce a naplní její Loans kolekci podrobnými Loan objekty.

    public Patron GetPopulatedPatron(Patron p)
    {
        Patron populated = new Patron
        {
            Id = p.Id,
            Name = p.Name,
            ImageName = p.ImageName,
            MembershipStart = p.MembershipStart,
            MembershipEnd = p.MembershipEnd,
            Loans = new List<Loan>()
        };
    
        foreach (Loan loan in Loans!)
        {
            if (loan.PatronId == p.Id)
            {
                populated.Loans.Add(GetPopulatedLoan(loan));
            }
        }
    
        return populated;
    }
    
  3. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    #selection refactor selection to `return new Patron` using LINQ
    
  4. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public Patron GetPopulatedPatron(Patron p)
    {
        return new Patron
        {
            Id = p.Id,
            Name = p.Name,
            ImageName = p.ImageName,
            MembershipStart = p.MembershipStart,
            MembershipEnd = p.MembershipEnd,
            Loans = Loans!
                .Where(loan => loan.PatronId == p.Id)
                .Select(GetPopulatedLoan)
                .ToList()
        };
    }
    

    Nejprve se k nahrazení smyčky foreach (Loan loan in Loans!) použije dotaz LINQ. Pomocí kódu LINQ můžete pomocí inicializátoru objektu přiřadit vlastnosti objektu novému Patron objektu. To snižuje potřebu samostatné populated instance objektu Patron . Aktualizovaný kód je celkově kratší a čitelnější.

    Kód používá vstupního patrona p k přiřazení některých základních vlastností k novému Patron objektu. Pak naplní kolekci Loans půjčkami, které jsou spojeny se vstupním patronem, transformuje každou půjčku GetPopulatedLoan pomocí metody.

    Můžete rozdělit řádek kódu LINQ, který naplní kolekci Loans :

    • Loans!: Výraz Loans! přistupuje k kolekci Loans . Operátor ! je operátor typu null-forgiving, který označuje, že vývojář má jistotu, že Loans není null. Před voláním metody byste měli zajistit, aby Loans byla správně inicializována GetPopulatedPatron .
    • .Where(loan => loan.PatronId == p.Id): Tento kód filtruje půjčky tak, aby zahrnoval pouze ty, které patří vstupnímu patronu p.
    • .Select(GetPopulatedLoan): Tento kód transformuje každou filtrovanou půjčku GetPopulatedLoan pomocí metody.
    • .ToList(): Převede výsledek na hodnotu List<Loan>.
  5. Pokud chcete přijmout navrženou aktualizaci, vyberte Přijmout.

    Teď, když jste viděli, jak refaktorovat metoduGetPopulatedPatron, můžete refaktorovat GetPopulatedLoanGetPopulatedBookItem, a GetPopulatedBook metody pro použití LINQ.

  6. Refaktoring GetPopulatedLoan, GetPopulatedBookItema GetPopulatedBook metody pomocí stejného přístupu.

    Pomocí následujících výzev můžete například refaktorovat tři metody:

    Pro metodu GetPopulatedLoan :

    #selection refactor selection to `return new Loan` using LINQ. Use `GetPopulatedBookItem` for the `BookItem` property. Use `Single` for BookItem and Patron properties.
    

    Pro metodu GetPopulatedBookItem :

    #selection refactor selection to `return new BookItem` using LINQ. Use `GetPopulatedBook` and `Single` for the `BookItem` property.
    

    Pro metodu GetPopulatedBook :

    #selection refactor selection to `return new Book` using LINQ. Use `Where` and `Select` for `Author` property. Use `First` author.
    
  7. Po přijetí navrhovaných aktualizací chvíli zkontrolujte změny kódu.

    Aktualizovaný kód by měl vypadat podobně jako následující kód:

    public Loan GetPopulatedLoan(Loan l)
    {
        return new Loan
        {
            Id = l.Id,
            BookItemId = l.BookItemId,
            PatronId = l.PatronId,
            LoanDate = l.LoanDate,
            DueDate = l.DueDate,
            ReturnDate = l.ReturnDate,
            BookItem = GetPopulatedBookItem(BookItems!.Single(bi => bi.Id == l.BookItemId)),
            Patron = Patrons!.Single(p => p.Id == l.PatronId)
        };
    }
    
    public BookItem GetPopulatedBookItem(BookItem bi)
    {
        return new BookItem
        {
            Id = bi.Id,
            BookId = bi.BookId,
            AcquisitionDate = bi.AcquisitionDate,
            Condition = bi.Condition,
            Book = GetPopulatedBook(Books!.Single(b => b.Id == bi.BookId))
        };
    }
    
    public Book GetPopulatedBook(Book b)
    {
        return new Book
        {
            Id = b.Id,
            Title = b.Title,
            AuthorId = b.AuthorId,
            Genre = b.Genre,
            ISBN = b.ISBN,
            ImageName = b.ImageName,
            Author = Authors!.Where(a => a.Id == b.AuthorId).Select(a => new Author {
                Id = a.Id,
                Name = a.Name
            }).First()
        };
    }
    
  8. Pomocí inteligentní akce Vysvětlit zobrazíte vysvětlení dotazů LINQ.

    Inteligentní akce Vysvětlit poskytuje podrobné vysvětlení dotazů LINQ použitých v kódu.

    Pomocí inteligentní akce Vysvětlit u metody můžete

    Author = Authors!.Where(a => a.Id == b.AuthorId).Select(a => new Author {
        Id = a.Id,
        Name = a.Name
    }).First()
    

    Inteligentní akce Vysvětlit poskytuje podrobné vysvětlení dotazu LINQ použitého k naplnění Author vlastnosti objektu Book .

    Vysvětlení může vypadat například takto:

    The active selection is a C# code snippet that assigns a value to the Author property. This value is derived from a collection of Author objects named Authors. The code uses LINQ (Language Integrated Query) to filter and transform the data within this collection.
    
    First, the Authors! expression uses the null-forgiving operator (!) to indicate that Authors is not null, even if the compiler might think otherwise. This is a way to suppress nullable warnings. The Where method is then called on the Authors collection to filter the elements. The lambda expression a => a.Id == b.AuthorId is used to find all Author objects where the Id matches the AuthorId property of another object b.
    
    After filtering, the Select method is used to project each filtered Author object into a new Author object. This is done by creating a new instance of the Author class and copying the Id and Name properties from the original Author object.
    
    Finally, the First method is called to retrieve the first element from the resulting sequence. This means that the Author property will be assigned the first Author object that matches the filter criteria and has been projected into a new Author instance.
    
    This approach ensures that the Author property is set to a new Author object with the same Id and Name as the first matching Author in the Authors collection.
    
  9. Sestavte řešení, abyste zajistili, že nedojde k žádným chybám.

    Zobrazí se upozornění. Prozatím je můžete ignorovat.

Refaktoring metod v JsonLoanRepository.cs pro použití LINQ

Třída JsonLoanRepository zahrnuje GetLoan metody a UpdateLoan metody přístupu k datům. Tyto dvě metody refaktorujete tak, že nahradíte smyčky foreach jazykem LINQ, abyste zlepšili čitelnost a udržovatelnost kódu.

K dokončení této části cvičení použijte následující kroky:

  1. Otevřete soubor JsonLoanRepository.cs.

  2. Vyberte metodu GetLoan.

    Metoda je navržená GetLoan tak, aby načítala půjčku podle ID.

    public async Task<Loan?> GetLoan(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        foreach (Loan loan in _jsonData.Loans!)
        {
            if (loan.Id == id)
            {
                Loan populated = _jsonData.GetPopulatedLoan(loan);
                return populated;
            }
        }
    
        return null;
    }
    
  3. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    Zadejte například následující výzvu:

    #selection refactor selection using LINQ with `_jsonData.Loans!. Use `Where`, `Select` and `GetPopulatedLoan` to return `FirstOrDefault`.
    
  4. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public async Task<Loan?> GetLoan(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        Loan? loan = _jsonData.Loans!
            .Where(l => l.Id == id)
            .Select(l => _jsonData.GetPopulatedLoan(l))
            .FirstOrDefault();
    
        return loan;
    }
    

    Aktualizovaný kód používá LINQ k filtrování kolekce půjček tak, aby zahrnoval pouze půjčku se zadaným ID. Všimněte si, že loan by se měla deklarovat jako nullable (Loan? loan). Pak pomocí metody transformuje půjčku GetPopulatedLoan a vrátí první výsledek. Pokud se nenajde žádná odpovídající půjčka, FirstOrDefault vrátí null. Metoda pak vrátí tento objekt půjčky, který může být null, pokud žádná půjčka se zadaným id neexistuje. Tento přístup zajišťuje, že vrácená půjčka je plně naplněna všemi nezbytnými souvisejícími daty a poskytuje komplexní přehled o záznamu půjčky.

    Tento kód lze dále zjednodušit:

    public async Task<Loan?> GetLoan(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        return _jsonData.Loans!
            .Where(l => l.Id == id)
            .Select(l => _jsonData.GetPopulatedLoan(l))
            .FirstOrDefault();
    
    }
    
  5. Pokud chcete přijmout aktualizovanou metodu GetLoan, vyberte Accept.

  6. Vyberte metodu UpdateLoan.

    public async Task UpdateLoan(Loan loan)
    {
        Loan? existingLoan = null;
        foreach (Loan l in _jsonData.Loans!)
        {
            if (l.Id == loan.Id)
            {
                existingLoan = l;
                break;
            }
        }
    
        if (existingLoan != null)
        {
            existingLoan.BookItemId = loan.BookItemId;
            existingLoan.PatronId = loan.PatronId;
            existingLoan.LoanDate = loan.LoanDate;
            existingLoan.DueDate = loan.DueDate;
            existingLoan.ReturnDate = loan.ReturnDate;
    
            await _jsonData.SaveLoans(_jsonData.Loans!);
    
            await _jsonData.LoadData();
        }
    }
    
  7. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    Zadejte například následující výzvu:

    #selection refactor selection using LINQ find an existing loan `_jsonData.Loans!. Replace existing loan.
    
  8. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public async Task UpdateLoan(Loan loan)
    {
        Loan? existingLoan = _jsonData.Loans!.FirstOrDefault(l => l.Id == loan.Id);
    
        if (existingLoan != null)
        {
            existingLoan.BookItemId = loan.BookItemId;
            existingLoan.PatronId = loan.PatronId;
            existingLoan.LoanDate = loan.LoanDate;
            existingLoan.DueDate = loan.DueDate;
            existingLoan.ReturnDate = loan.ReturnDate;
    
            await _jsonData.SaveLoans(_jsonData.Loans!);
    
            await _jsonData.LoadData();
        }
    }
    

    Aktualizovaný kód používá LINQ k vyhledání existující půjčky v kolekci půjček. Pak aktualizuje stávající půjčku pomocí nových dat o půjčkách. Metoda pak uloží aktualizovanou kolekci půjček a znovu načte data. Tento přístup zajišťuje, že se data o půjčkách správně aktualizují a že se změny uchovávají v úložišti dat.

    Můžete také přidat kód, který zajistí načtení dat před spuštěním metody:

    public async Task UpdateLoan(Loan loan)
    {
        await _jsonData.EnsureDataLoaded();
    
        Loan? existingLoan = _jsonData.Loans!.FirstOrDefault(l => l.Id == loan.Id);
    
        if (existingLoan != null)
        {
            existingLoan.BookItemId = loan.BookItemId;
            existingLoan.PatronId = loan.PatronId;
            existingLoan.LoanDate = loan.LoanDate;
            existingLoan.DueDate = loan.DueDate;
            existingLoan.ReturnDate = loan.ReturnDate;
    
            await _jsonData.SaveLoans(_jsonData.Loans!);
    
            await _jsonData.LoadData();
        }
    }
    
    
  9. Chcete-li přijmout aktualizovanou metodu UpdateLoan, vyberte Přijmout.

  10. Sestavte řešení, abyste zajistili, že nedojde k žádným chybám.

    Zobrazí se upozornění. Prozatím je můžete ignorovat.

Refaktoring metod v JsonPatronRepository pro použití LINQ

Třída JsonPatronRepository obsahuje SearchPatrons, GetPatrona UpdatePatron metody a je to skvělý kandidát na optimalizaci. Tyto metody refaktorujete a nahradíte smyčky foreach jazykem LINQ, aby se zlepšila čitelnost a udržovatelnost kódu.

K dokončení této části cvičení použijte následující kroky:

  1. Otevřete soubor JsonPatronRepository.cs.

  2. Vyberte metodu SearchPatrons.

    Metoda SearchPatrons je navržena tak, aby hledala patrony podle jména.

    public async Task<List<Patron>> SearchPatrons(string searchInput)
    {
        await _jsonData.EnsureDataLoaded();
    
        List<Patron> searchResults = new List<Patron>();
        foreach (Patron patron in _jsonData.Patrons)
        {
            if (patron.Name.Contains(searchInput))
            {
                searchResults.Add(patron);
            }
        }
        searchResults.Sort((p1, p2) => String.Compare(p1.Name, p2.Name));
    
        searchResults = _jsonData.GetPopulatedPatrons(searchResults);
    
        return searchResults;
    }
    
  3. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    Zadejte například následující výzvu:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Replace the loop with `Where`, `OrderBy`, and `GetPopulatedPatrons`.
    
  4. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public async Task<List<Patron>> SearchPatrons(string searchInput)
    {
        await _jsonData.EnsureDataLoaded();
    
        List<Patron> searchResults = _jsonData.Patrons!
            .Where(patron => patron.Name.Contains(searchInput))
            .OrderBy(patron => patron.Name)
            .ToList();
    
        searchResults = _jsonData.GetPopulatedPatrons(searchResults);
    
        return searchResults;
    }
    
  5. Pokud chcete přijmout aktualizovanou metodu SearchPatrons, vyberte Přijmout.

  6. Vyberte metodu GetPatron.

    Metoda GetPatron je navržena tak, aby vrátila patrona odpovídající zadanému id.

    public async Task<Patron?> GetPatron(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        foreach (Patron patron in _jsonData.Patrons!)
        {
            if (patron.Id == id)
            {
                Patron populated = _jsonData.GetPopulatedPatron(patron);
                return populated;
            }
        }
        return null;
    }
    
  7. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    Zadejte například následující výzvu:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Use `Where`, `Select` and `GetPopulatedPatron` to return `FirstOrDefault`
    
  8. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public async Task<Patron?> GetPatron(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        var patron = _jsonData.Patrons!
            .Where(p => p.Id == id)
            .Select(p => _jsonData.GetPopulatedPatron(p))
            .FirstOrDefault();
    
        return patron;
    }
    

    Tento kód lze dále zjednodušit:

    public async Task<Patron?> GetPatron(int id)
    {
        await _jsonData.EnsureDataLoaded();
    
        return _jsonData.Patrons!
            .Where(p => p.Id == id)
            .Select(p => _jsonData.GetPopulatedPatron(p))
            .FirstOrDefault();
    }
    
  9. Pokud chcete přijmout aktualizovanou metodu GetPatron, vyberte Accept.

  10. Vyberte metodu UpdatePatron.

    Metoda UpdatePatron je navržena tak, aby aktualizovala patrona zadaným id.

    
    public async Task UpdatePatron(Patron patron)
    {
        await _jsonData.EnsureDataLoaded();
        var patrons = _jsonData.Patrons!;
        Patron existingPatron = null;
        foreach (var p in patrons)
        {
            if (p.Id == patron.Id)
            {
                existingPatron = p;
                break;
            }
        }
        if (existingPatron != null)
        {
            existingPatron.Name = patron.Name;
            existingPatron.ImageName = patron.ImageName;
            existingPatron.MembershipStart = patron.MembershipStart;
            existingPatron.MembershipEnd = patron.MembershipEnd;
            existingPatron.Loans = patron.Loans;
            await _jsonData.SavePatrons(patrons);
            await _jsonData.LoadData();
        }
    }
    
  11. Otevřete vložený chat a zadejte výzvu, která refaktoruje metodu pomocí LINQ.

    Zadejte například následující výzvu:

    #selection refactor selection using LINQ to find `patron` in `_jsonData.Patrons!. Replace existing patron with `patron`.
    
  12. Projděte si navrženou aktualizaci za minutu.

    Navrhovaná aktualizace by měla vypadat podobně jako v následujícím kódu:

    public async Task UpdatePatron(Patron patron)
    {
        await _jsonData.EnsureDataLoaded();
        var patrons = _jsonData.Patrons!;
        var existingPatron = patrons.FirstOrDefault(p => p.Id == patron.Id);
        if (existingPatron != null)
        {
            existingPatron.Name = patron.Name;
            existingPatron.ImageName = patron.ImageName;
            existingPatron.MembershipStart = patron.MembershipStart;
            existingPatron.MembershipEnd = patron.MembershipEnd;
            existingPatron.Loans = patron.Loans;
            await _jsonData.SavePatrons(patrons);
            await _jsonData.LoadData();
        }
    }
    
  13. Pokud chcete přijmout aktualizovanou metodu UpdatePatron, vyberte Přijmout.

Kontrola práce

Pomocí následujících kroků zkontrolujte svou práci:

  1. Chcete-li řešení vyčistit, klikněte pravým tlačítkem myši AccelerateAppDevGitHubCopilota pak vyberte Vyčistit.

    Tato akce odebere všechny artefakty sestavení z předchozího sestavení. Čištění řešení efektivně resetuje datové soubory JSON na původní hodnoty během (ve výstupním adresáři).

  2. Sestavte aplikaci a ujistěte se, že nedošlo k žádným chybám.

  3. Aplikaci spusťte.

    Aplikaci můžete spustit ze zobrazení Průzkumník řešení tak, že kliknete pravým tlačítkem na Library.Console projekt, vyberete Ladit a pak vyberete Spustit novou instanci.

  4. Po zobrazení výzvy k zadání jména patrona zadejte 1 a stiskněte Enter.

  5. Na příkazovém řádku "Matching Patrons" zadejte 2 a stiskněte Enter.

  6. Na příkazovém řádku "Book Loans" zadejte 1 a stiskněte Enter.

  7. Na příkazovém řádku Vstupní možnosti zadejte r a stiskněte Enter.

  8. Ověřte, že se zobrazila zpráva "Kniha byla úspěšně vrácena".

  9. Pokud chcete zahájit nové hledání, zadejte s a stiskněte Enter.

  10. Po zobrazení výzvy k zadání jména patrona zadejte 1 a stiskněte Enter.

  11. Na příkazovém řádku "Matching Patrons" zadejte 2 a stiskněte Enter.

  12. Ověřte, že je označena první kniha půjčka Returned: True.

  13. Na příkazovém řádku Vstupní možnosti zadejte q a stiskněte Enter.

  14. Zastavte aplikaci.