练习 - 使用 GitHub Copilot 工具开发代码功能

已完成

你和同事正在开会讨论图书馆应用程序的开发目标。 你希望改善图书管理员和借阅者的用户体验。 你们讨论了可以添加到该应用程序的多项新功能。

你同意开发以下功能:

  • 书籍可借状态:可让图书管理员确定书籍的可借状态。 此功能应显示一条消息,指出某书籍是否可供借阅,如果该书籍当前已借给其他借阅者,该消息会显示归还截止日期。

  • 书籍借阅记录:可让图书管理员将书籍借给借阅者(如果该书籍可供借阅)。 此功能应显示借阅者接收借阅书籍的选项,使用新的借阅记录更新 Loans.json,并显示借阅者的已更新借阅详细信息。

  • 书籍预留:可让图书管理员为借阅者预留书籍(除非该书籍已预留)。 此功能应实现新的书籍预留过程。 此功能可能需要创建新的 Reservations.json 文件,以及支持预留过程所需的新类和接口。

你们每个人将负责开发其中的一项新功能,然后重新组合。 你将负责开发用于确定书籍可借状态的功能。 你的同事负责开发向借阅者借书的功能。 最后一项功能(为借阅者预留书籍)将在上述两项功能完成后进行开发。

在本练习中,你需要完成以下任务:

  1. 在代码存储库中创建“书籍可借状态”分支。

  2. 开发新的“书籍可借状态”功能。

    • 使用 GitHub Copilot 建议来帮助更快、更准确地实现代码。
    • 将代码更新同步到远程存储库的“书籍可借状态”分支。
  3. 创建一个拉取请求,以将更改合并到存储库的 main 分支中。

在存储库中创建新分支

在开始开发新的“书籍可借状态”功能之前,需要在存储库中创建新分支。 这样便可以开发新功能且不会影响存储库的 main 分支。 准备就绪后,可以将新功能合并到 main 分支中。

请使用以下步骤完成本练习的这一部分:

  1. 确保已在 Visual Studio Code 中打开 AccelerateDevGitHubCopilot 解决方案。

  2. 选择“源代码管理”视图,并确保本地存储库已与远程存储库同步(“拉取”或“同步”)。

  3. 在窗口左下角,选择“main”

  4. 若要创建新分支,请键入 书籍可用性 ,然后选择“ + 创建新分支”。

  5. 若要将新分支推送到远程存储库,请选择“发布分支”

开发一项功能,使图书管理员能够确定书籍的可借状态

在本练习的本部分,你将使用 GitHub Copilot 来帮助为图书馆应用程序实现一项新功能。 该新功能使图书管理员能够确定书籍的可借状态。

书籍可借状态功能应包括以下代码更新:

  • 将新的 SearchBooks 操作添加到 CommonActions
  • 更新 ConsoleApp.cs 中的 WriteInputOptions 方法。 添加对新 CommonActions.SearchBooks 选项的支持。 显示用于检查书籍是否可供借阅的选项。
  • 更新 ConsoleApp.cs 中的 ReadInputOptions 方法。 添加对新 CommonActions.SearchBooks 选项的支持。
  • 更新 ConsoleApp.cs 中的 PatronDetails 方法。 在调用 ReadInputOptions 之前,将 CommonActions.SearchBooks 添加到 options。 添加 else if 来处理 SearchBooks 操作。 else if 块应该调用名为 SearchBooks 的新方法。
  • 在 ConsoleApp.cs 中创建新的 SearchBooks 方法。 SearchBooks 方法应该读取用户提供的书籍标题。 检查某书籍是否可供借阅,并显示一条消息,指出“book.title 可供借阅”或“book.title 已借给其他借阅者。 归还截止日期为 loan.DueDate

请使用以下步骤完成本练习的这一部分:

  1. 打开“解决方案资源管理器”视图。

  2. 打开 CommonActions.cs 文件,然后选择 CommonActions 枚举。

    需要将新的 SearchBooks 操作添加到 CommonActions

  3. 打开内联聊天,然后输入以下提示:

    Update selection to include a new `SearchBooks` action.
    

    GitHub Copilot 应该建议进行代码更新,以将新的 SearchBooks 操作添加到 CommonActions 枚举。

  4. 查看建议的更新,然后选择“接受”

    public enum CommonActions
    {
        Repeat = 0,
        Select = 1,
        Quit = 2,
        SearchPatrons = 4,
        RenewPatronMembership = 8,
        ReturnLoanedBook = 16,
        ExtendLoanedBook = 32,
        SearchBooks = 64
    }
    
  5. 打开 ConsoleApp.cs 文件。

  6. 找到并选择 WriteInputOptions 方法。

    需要添加对新 CommonActions.SearchBooks 选项的支持。 显示用于检查书籍是否可供借阅的选项。

  7. 打开内联聊天,然后输入以下提示:

    Update selection to include an option for the `CommonActions.SearchBooks` action. Use the letter "b" and the message "to check for book availability".
    

    GitHub Copilot 应该建议进行代码更新,以便为 SearchBooks 操作添加新的 if 块。

  8. 查看建议的更新,然后选择“接受”

    建议的更新应类似于以下代码片段:

    static void WriteInputOptions(CommonActions options)
    {
        Console.WriteLine("Input Options:");
        if (options.HasFlag(CommonActions.ReturnLoanedBook))
        {
            Console.WriteLine(" - \"r\" to mark as returned");
        }
        if (options.HasFlag(CommonActions.ExtendLoanedBook))
        {
            Console.WriteLine(" - \"e\" to extend the book loan");
        }
        if (options.HasFlag(CommonActions.RenewPatronMembership))
        {
            Console.WriteLine(" - \"m\" to extend patron's membership");
        }
        if (options.HasFlag(CommonActions.SearchPatrons))
        {
            Console.WriteLine(" - \"s\" for new search");
        }
        if (options.HasFlag(CommonActions.SearchBooks))
        {
            Console.WriteLine(" - \"b\" to check for book availability");
        }
        if (options.HasFlag(CommonActions.Quit))
        {
            Console.WriteLine(" - \"q\" to quit");
        }
        if (options.HasFlag(CommonActions.Select))
        {
            Console.WriteLine("Or type a number to select a list item.");
        }
    }
    
  9. 稍微向上滚动,以找到并选择 ReadInputOptions 方法。

    需要添加对新 CommonActions.SearchBooks 选项的支持。 包含一个案例来处理用户选择 SearchBooks 操作的情况。

  10. 打开内联聊天,然后输入以下提示:

    Update selection to include an option for the `CommonActions.SearchBooks` action.
    

    GitHub Copilot 应该建议进行代码更新,以添加新的 case 来处理用户选择 SearchBooks 操作的情况。

  11. 查看建议的更新,然后选择“接受”

    建议的更新应类似于以下代码片段:

    static CommonActions ReadInputOptions(CommonActions options, out int optionNumber)
    {
        CommonActions action;
        optionNumber = 0;
        do
        {
            Console.WriteLine();
            WriteInputOptions(options);
            string? userInput = Console.ReadLine();
    
            action = userInput switch
            {
                "q" when options.HasFlag(CommonActions.Quit) => CommonActions.Quit,
                "s" when options.HasFlag(CommonActions.SearchPatrons) => CommonActions.SearchPatrons,
                "m" when options.HasFlag(CommonActions.RenewPatronMembership) => CommonActions.RenewPatronMembership,
                "e" when options.HasFlag(CommonActions.ExtendLoanedBook) => CommonActions.ExtendLoanedBook,
                "r" when options.HasFlag(CommonActions.ReturnLoanedBook) => CommonActions.ReturnLoanedBook,
                "b" when options.HasFlag(CommonActions.SearchBooks) => CommonActions.SearchBooks,
                _ when int.TryParse(userInput, out optionNumber) => CommonActions.Select,
                _ => CommonActions.Repeat
            };
    
            if (action == CommonActions.Repeat)
            {
                Console.WriteLine("Invalid input. Please try again.");
            }
        } while (action == CommonActions.Repeat);
        return action;
    }
    
  12. 向下滚动,以找到并选择 PatronDetails 方法。

    需要完成以下两项操作:

    • 在调用 ReadInputOptions 之前,需要将 CommonActions.SearchBooks 添加到 options
    • 还需要添加 else if 来处理 SearchBooks 操作。 else if 块应该调用名为 SearchBooks 的新方法。

    可以同时处理这两项操作。

  13. 打开内联聊天,然后输入以下提示:

    Update selection to add `CommonActions.SearchBooks` to `options` before calling `ReadInputOptions`. Add an `else if` block to handle the `SearchBooks` action. The `else if` block should call a new method named `SearchBooks`.
    

    GitHub Copilot 应该建议进行代码更新,以便在调用 ReadInputOptions 之前将 CommonActions.SearchBooks 添加到 options

  14. 查看建议的更新,然后选择“接受”

    async Task<ConsoleState> PatronDetails()
    {
        Console.WriteLine($"Name: {selectedPatronDetails.Name}");
        Console.WriteLine($"Membership Expiration: {selectedPatronDetails.MembershipEnd}");
        Console.WriteLine();
        Console.WriteLine("Book Loans:");
        int loanNumber = 1;
        foreach (Loan loan in selectedPatronDetails.Loans)
        {
            Console.WriteLine($"{loanNumber}) {loan.BookItem!.Book!.Title} - Due: {loan.DueDate} - Returned: {(loan.ReturnDate != null).ToString()}");
            loanNumber++;
        }
    
        CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership | CommonActions.SearchBooks;
        CommonActions action = ReadInputOptions(options, out int selectedLoanNumber);
        if (action == CommonActions.Select)
        {
            if (selectedLoanNumber >= 1 && selectedLoanNumber <= selectedPatronDetails.Loans.Count())
            {
                var selectedLoan = selectedPatronDetails.Loans.ElementAt(selectedLoanNumber - 1);
                selectedLoanDetails = selectedPatronDetails.Loans.Where(l => l.Id == selectedLoan.Id).Single();
                return ConsoleState.LoanDetails;
            }
            else
            {
                Console.WriteLine("Invalid book loan number. Please try again.");
                return ConsoleState.PatronDetails;
            }
        }
        else if (action == CommonActions.Quit)
        {
            return ConsoleState.Quit;
        }
        else if (action == CommonActions.SearchPatrons)
        {
            return ConsoleState.PatronSearch;
        }
        else if (action == CommonActions.RenewPatronMembership)
        {
            var status = await _patronService.RenewMembership(selectedPatronDetails.Id);
            Console.WriteLine(EnumHelper.GetDescription(status));
            // reloading after renewing membership
            selectedPatronDetails = (await _patronRepository.GetPatron(selectedPatronDetails.Id))!;
            return ConsoleState.PatronDetails;
        }
        else if (action == CommonActions.SearchBooks)
        {
            return await SearchBooks();
        }
    
        throw new InvalidOperationException("An input option is not handled.");
    }
    

    注意

    内联聊天建议还可能为 SearchBooks 方法创建存根代码。

  15. 请花点时间考虑一下 SearchBooks 方法的过程要求。

    该方法需要执行哪些操作? 它应该返回哪些信息? 它是否需要参数?

    SearchBooks 方法应实现以下过程:

    1. 提示用户输入书籍标题。

    2. 读取用户提供的书籍标题。

    3. 检查书籍是否可供借阅

    4. 显示一条消息,其中指明了以下选项之一:

      • book.title 可供借阅”
      • book.title 已借给其他借阅者。 归还截止日期为 loan.DueDate

    若要生成消息选项,代码需要访问以下 JSON 文件:

    • 需要提供 Books.json 来查找匹配的 TitleBookId
    • 需要提供 Loans.json 来查找匹配的 BookItemIdReturnDateDueDateBookItemIdBooks.json 中的 BookId 相同。
  16. 确保在 ConsoleApp.cs 文件中创建了以下 SearchBooks 方法:

    async Task<ConsoleState> SearchBooks()
    {
    
        return ConsoleState.PatronDetails;
    }
    

    注意

    请务必删除 GitHub Copilot 创建的所有代码注释。 不必要和不准确的注释会对 GitHub Copilot 的建议产生负面影响。

  17. 选择 SearchBooks 方法。

  18. 打开内联聊天,然后输入以下提示:

    Update selection to obtain a book title. Prompt the user to "Enter a book title to search for". Read the user input and ensure the book title isn't null.
    

    GitHub Copilot 应该建议进行代码更新,以捕获用户提供的书籍标题。

  19. 查看建议的更新,然后选择“接受”

    async Task<ConsoleState> SearchBooks()
    {
        string? bookTitle = null;
        while (String.IsNullOrWhiteSpace(bookTitle))
        {
            Console.Write("Enter a book title to search for: ");
            bookTitle = Console.ReadLine();
        }
    
        // Perform book search logic here
    
        return ConsoleState.PatronDetails;
    }
    
  20. 选择 SearchBooks 方法。

    注意

    GitHub Copilot 可能会创建一个单独的方法来处理用户输入的书名。 可以继续开发 SearchBooks 方法中的主逻辑。

  21. 打开“聊天”视图。

  22. 将以下文件添加到“聊天”上下文:ConsoleApp.cs、JsonData.cs、JsonLoanRepository.cs、Books.json、Loans.json、BookItems.json。

  23. 输入以下提示:

    @workspace  Explain how to update the `SearchBooks` method and ConsoleApps class to find a matching book title in the `Books.json` file. Use the user supplied book title to find a matching book. If a book is found, use Loans.json to check if the book is available for loan. If the book has been returned, display a message stating "`book.title` is available for loan". If the book is on loan, display a message stating "`book.title` is on loan to another patron. The return due date is `loan.DueDate`".
    
  24. 请花点时间来查看建议的更新。

    GitHub Copilot 应提出类似于以下建议的更新:

    若要更新 SearchBooks 方法和 ConsoleApp 类以在 Books.json 文件中查找匹配的书籍标题,并检查该书籍是否可借阅,请执行以下步骤:

    a。 在 JsonData 类中添加按书名搜索书籍的方法。 b. 更新 ConsoleApp 类中的 SearchBooks 方法以使用此新方法。 c. 检查书籍的借阅状态并显示相应的消息。

    以下是更新后的代码:

    步骤 1:在 JsonData 类中添加按书名搜索书籍的方法

    public class JsonData
    {
        // Existing code...
    
        public Book? SearchBookByTitle(string title)
        {
            return Books?.FirstOrDefault(b => b.Title.Equals(title, StringComparison.OrdinalIgnoreCase));
        }
    }
    

    步骤 2:更新 ConsoleApp 类中的 SearchBooks 方法

    public class ConsoleApp
    {
        // Existing fields...
    
        JsonData _jsonData;
    
        public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository, JsonData jsonData)
        {
            _patronRepository = patronRepository;
            _loanRepository = loanRepository;
            _loanService = loanService;
            _patronService = patronService;
            _jsonData = jsonData;
        }
    
        // Existing methods...
    
        async Task<ConsoleState> SearchBooks()
        {
            string bookTitle = ReadBookTitle();
    
            Book? book = _jsonData.SearchBookByTitle(bookTitle);
    
            if (book == null)
            {
                Console.WriteLine($"No book found with title: {bookTitle}");
                return ConsoleState.PatronDetails;
            }
    
            Loan? loan = _jsonData.Loans?.FirstOrDefault(l => l.BookItemId == book.Id && l.ReturnDate == null);
    
            if (loan == null)
            {
                Console.WriteLine($"{book.Title} is available for loan.");
            }
            else
            {
                Console.WriteLine($"{book.Title} is on loan to another patron. The return due date is {loan.DueDate}.");
            }
    
            return ConsoleState.PatronDetails;
        }
    
        // Existing methods...
    }
    

    步骤 3:更新 Program.cs 以将 JsonData 传递给 ConsoleApp

    using Microsoft.Extensions.DependencyInjection;
    using Library.Infrastructure.Data;
    using Library.ApplicationCore;
    using Microsoft.Extensions.Configuration;
    
    var services = new ServiceCollection();
    
    var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appSettings.json")
    .Build();
    
    services.AddSingleton<IConfiguration>(configuration);
    
    services.AddScoped<IPatronRepository, JsonPatronRepository>();
    services.AddScoped<ILoanRepository, JsonLoanRepository>();
    services.AddScoped<ILoanService, LoanService>();
    services.AddScoped<IPatronService, PatronService>();
    
    services.AddSingleton<JsonData>();
    services.AddSingleton<ConsoleApp>();
    
    var servicesProvider = services.BuildServiceProvider();
    
    var consoleApp = servicesProvider.GetRequiredService<ConsoleApp>();
    consoleApp.Run().Wait();
    

    通过这些更改,ConsoleApp 类中的 SearchBooks 方法现在将在 Books.json 文件中按书名搜索书籍,并在 Loans.json 文件中检查其借阅状态。 如果书籍可供借阅,它将显示一条消息,指明该书可供借阅。 如果书籍已借出,它将显示一条消息,指明该书已借出,并提供归还截止日期。

  25. 将建议的方法添加到 JsonData 类的末尾。

    public Book? SearchBookByTitle(string title)
    {
        return Books?.FirstOrDefault(b => b.Title.Equals(title, StringComparison.OrdinalIgnoreCase));
    }
    
  26. 使用建议的更新来更新 Program.cs 文件。

    using Microsoft.Extensions.DependencyInjection;
    using Library.Infrastructure.Data;
    using Library.ApplicationCore;
    using Microsoft.Extensions.Configuration;
    
    var services = new ServiceCollection();
    
    var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appSettings.json")
    .Build();
    
    services.AddSingleton<IConfiguration>(configuration);
    
    services.AddScoped<IPatronRepository, JsonPatronRepository>();
    services.AddScoped<ILoanRepository, JsonLoanRepository>();
    services.AddScoped<ILoanService, LoanService>();
    services.AddScoped<IPatronService, PatronService>();
    
    services.AddSingleton<JsonData>();
    services.AddSingleton<ConsoleApp>();
    
    var servicesProvider = services.BuildServiceProvider();
    
    var consoleApp = servicesProvider.GetRequiredService<ConsoleApp>();
    consoleApp.Run().Wait();
    
  27. JsonData _jsonData; 字段声明添加到类构造函数前面的 ConsoleApp 类中。

  28. JsonData jsonData 参数添加到 ConsoleApp 类构造函数,并使用它来初始化构造函数内的 _jsonData 字段。

    更新的类构造函数应类似于以下代码片段:

    public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository, JsonData jsonData)
    {
        _patronRepository = patronRepository;
        _loanRepository = loanRepository;
        _loanService = loanService;
        _patronService = patronService;
        _jsonData = jsonData;
    }
    
  29. 请注意,JsonData 在 ConsoleApp 类中无法识别。

    需要将 using Library.Infrastructure.Data; 添加到 ConsoleApp.cs 文件顶部。

  30. 确保 using Library.Infrastructure.Data; 语句已添加到 ConsoleApp.cs 文件的顶部。

  31. 使用代码建议来更新 SearchBooks 方法:

    建议的代码应使用 LINQ 查询按书名搜索书籍。 如果找到该书,则使用另一个 LINQ 查询来确定该书是否已借出。 该代码还包含可根据搜索结果显示书籍可借状态的逻辑。 可以通过多种方式实现用于显示响应消息的逻辑。 以下代码片段中提供了一个示例。

    以下代码片段演示了 SearchBooks 方法的一种可能实现:

    async Task<ConsoleState> SearchBooks()
    {
        string bookTitle = ReadBookTitle();
    
        Book? book = _jsonData.SearchBookByTitle(bookTitle);
    
        if (book == null)
        {
            Console.WriteLine($"No book found with title: {bookTitle}");
            return ConsoleState.PatronDetails;
        }
    
        Loan? loan = _jsonData.Loans?.FirstOrDefault(l => l.BookItemId == book.Id && l.ReturnDate == null);
    
        if (loan == null)
        {
            Console.WriteLine($"{book.Title} is available for loan.");
        }
        else
        {
            Console.WriteLine($"{book.Title} is on loan to another patron. The return due date is {loan.DueDate}.");
        }
    
        return ConsoleState.PatronDetails;
    }
    
  32. 选择 SearchBooks 方法。

  33. 打开“聊天”视图,然后输入以下提示:

    Explain the LINQ queries and the evaluation of the book's availability status.
    
  34. 请花点时间查看 GitHub Copilot 提供的解释。

    对于检查书籍是否已借出的查询,应会看到类似于以下解释的说明:

    **Search for the Loan Status of the Book**
    
    Loan? loan = _jsonData.Loans?.FirstOrDefault(l => l.BookItemId == book.Id && l.ReturnDate == null);
    
    - _jsonData.Loans: Accesses the list of loans from the JsonData class.
    
    - ?.: The null-conditional operator ensures that if _jsonData.Loans is null, the entire expression will return null without throwing a NullReferenceException.
    
    - FirstOrDefault: A LINQ method that returns the first element in the collection that matches the specified condition, or null if no such element is found.
    
    - Lambda Expression: l => l.BookItemId == book.Id && l.ReturnDate == null
    
        - l.BookItemId == book.Id: Checks if the BookItemId of the loan matches the Id of the book being searched.
    
        - l.ReturnDate == null: Checks if the loan's ReturnDate is null, indicating that the book is currently on loan and has not been returned.
    
    - Result: If a matching loan is found, it is assigned to the loan variable. If no matching loan is found, loan is null.
    
    **Evaluation of the Book's Availability Status**
    
    After executing the LINQ queries, the method evaluates the availability status of the book:
    
      - If `loan` is `null`, the book has been returned. The method prints that the book is available for loan.
      - If `loan` is not `null`, the book is currently on loan (no return date). The method prints that the book is on loan and provides the date when the book should be returned.
    
    
  35. 验证“检查书籍是否已借出”查询所实现的逻辑

    Null 条件运算符:?. 运算符是 null 条件运算符。 它确保当 _jsonData.Loansnull 时,整个表达式将计算为 null 而不会引发 NullReferenceException

    Lambda 表达式:lambda 表达式 l => l.BookItemId == book.Id && l.ReturnDate == null 定义 FirstOrDefault 方法的条件。 它检查每个 loan 对象 l,判断它的 BookItemId 是否与 book 对象的 Id 匹配,以及它的 ReturnDate 是否为 null

    此代码尝试在 _jsonData.Loans 集合中,查找其 BookItemId 与给定 bookId 匹配,且 ReturnDatenull 的第一个 loan。 如果找不到这种 loan 或者 _jsonData.Loansnull,则 loan 将设置为 null

    注意

    大多数现代图书馆都藏有同一本书的多个复印本。 此代码假设每本书只有一个复印本。 如果图书馆藏有同一本书的多个复印本,则需要更新代码以处理同一本书的多个借阅记录。 对于此次培训,我们假设每本书只有一个复印本,并且提供的逻辑足以解决需要。

  36. 生成解决方案以确保不会出现错误。

    你将看到警告消息,但不应出现任何错误。

    若要在“解决方案资源管理器”视图中生成解决方案,请右键单击“AccelerateDevGitHubCopilot”,然后选择“生成”

将更改与远程存储库同步

  1. 选择“源代码管理”视图。

  2. 确保更新的文件列在“更改”下

  3. 使用 GitHub Copilot 为“提交”生成消息

  4. 若要暂存并提交更改,请选择“提交”,然后选择“是”

  5. 将更改同步(或推送)到远程存储库。

检查你的工作

在本练习的本部分,你需要完成以下任务:

  1. 验证新功能是否能够正确确定书籍的可借状态。
  2. 创建一个拉取请求,以将更改合并到存储库的 main 分支中。

验证新功能是否按预期工作

由于没有自动化测试,你可以使用手动测试来验证新功能是否按预期工作。 必须使用可验证的数据源。 在本例中,可以使用 Books.jsonLoans.json 文件来验证新功能是否正确报告了书籍的可借状态。

请使用以下步骤完成本练习的这一部分:

  1. 打开“解决方案资源管理器”视图。

  2. 若要运行该应用程序,请右键单击“Library.Console”,选择“调试”,然后选择“启动新实例”

  3. 当系统提示你输入借阅者姓名时,请键入 1,然后按 Enter

    你应会看到与搜索查询匹配的借阅者列表。

  4. 在“输入选项”提示处键入 2,然后按 Enter

    输入 2 会选择列表中的第二位借阅者

    你应会看到借阅者的姓名和会员状态,以及书籍的借阅详细信息。

  5. 在“输入选项”提示处键入 b,然后按 Enter

    输入 b 会选择用于搜索书籍可借状态的选项

    你应会看到用于输入书籍标题的提示。

  6. 键入“书籍 1”,然后按 Enter

    在下载的原始数据中,“书籍 1”当前已借给“借阅者 49”,因此不可借阅

  7. 验证应用程序是否显示了一条消息,指出该书籍已借给另一位借阅者。

  8. 验证“书籍 9”是否已由“借阅者 1”归还

    在上一个练习中,在对图书馆应用程序进行测试期间,你已让“借阅者 1”归还“书籍 9”。 如果应用程序显示“书籍 9”尚未由“借阅者 1”归还,请使用输入选项选择并归还“书籍 9”,然后继续

    注意

    Library.Console.csproj 文件确保在生成应用程序时将 JSON 数据文件复制到输出目录。 但是,执行“清理”或“重新生成”操作实际上会重置数据。 重复“生成”操作不会重置输出目录 (/bin/Debug/net8.0/) 中的数据。

  9. 在“输入选项”提示处键入 b,然后按 Enter

  10. 键入“书籍 9”,然后按 Enter

  11. 验证应用程序是否显示了一条消息,指出该书籍可供借阅。

  12. 在“输入选项”提示处键入 q,然后按 Enter

  13. 停止调试会话。

  14. 打开 Loans.json 文件。

    Loans.json 文件用于跟踪每本书的借阅状态。 可以使用 Loans.json 文件来验证书籍 1 和书籍 9 的可借状态是否正确。

    更新的 Loans.json 文件应位于 Library.Console\bin\Debug\net8.0\Json 文件夹或 Library.Console\Json 文件夹中。

    • 如果使用 Visual Studio Code 调试器运行应用,则更新的 Loans.json 文件应位于 Library.Console\bin\Debug\net8.0\Json 文件夹中。

    • 如果从 AccelerateDevGitHubCopilot\src\Library.Console> 文件夹使用 dotnet run 命令来运行应用,则更新的 Loans.json 文件应位于 Library.Console\Json 文件夹中。

  15. 验证借阅 ID 37 和借阅 ID 46 是否均属于书籍 1 ("BookItemId": 1)。

    • 借阅 ID 37 应包含 ReturnDate 值 (2024-01-17)
    • 借阅 ID 46 不应包含 ReturnDate 值。 ReturnDate 值应为 null

    ReturnDate 值用于确定该书籍当前是否已借出。 如果 ReturnDate 值为 null,则认为该书籍已借出。

  16. 验证借阅 ID 22 是否属于书籍 9 ("BookItemId": 9),并且 ReturnDate 值是否设置为当天的日期。

    如果你当前正在调试器中运行,并且在对 Loans.json 文件进行更改后清理了解决方案,则这些更改将会丢失。 清理解决方案后,下次运行应用程序时,Loans.json 文件将重置为原始数据。 可以手动更新 Loans.json 文件来测试书籍 1 和书籍 9 的可借状态。

创建拉取请求以将更改合并到 main 分支

你已开发完新的功能,它使图书管理员能够确定书籍的可借状态。 现在需要将更改合并到存储库的 main 分支中。 可以创建一个拉取请求,以将更改合并到 main 分支中。

请使用以下步骤完成本练习的这一部分:

  1. 在 Web 浏览器中打开 GitHub 存储库。

  2. 打开“拉取请求”选项卡

  3. 选择“新建拉取请求”

  4. 在“比较更改”下,确保为 main 分支配置了 base

  5. 确保为 book-availability 分支配置了 compare

    配置分支后,将显示 main 和 book-availability 之间的更改比较结果。 应会看到已更新的每个文件的更改。

  6. 选择“创建拉取请求”

  7. 输入拉取请求的标题和说明。

    可以使用以下标题和说明:

    • 标题:feat:在 ConsoleApp 中添加书籍搜索功能
    • 说明:此拉取请求添加了一项新功能,使图书馆员能够确定书籍的可用性状态。 此功能在 CommonActions 中包含新的 SearchBooks 操作,对 ConsoleApp 中的 WriteInputOptionsReadInputOptionsPatronDetails 方法进行更新,并在 ConsoleApp 中添加新的 SearchBooks 方法。

    注意

    订阅了 GitHub Copilot Enterprise 的企业会员可以使用 GitHub Copilot 在 GitHub.com 上生成拉取请求的摘要。 可以使用摘要来帮助审阅者了解更改,或快速了解你正在审阅的拉取请求中的更改。 选择“GitHub Actions”,然后选择“摘要”以生成拉取请求的摘要

    下面是使用 GitHub Copilot Enterprise 帐户生成的拉取请求摘要的示例:

    显示使用 GitHub Copilot Enterprise 帐户生成的拉取请求摘要的屏幕截图。

  8. 确保标题和说明反映了你的代码更新,然后选择“创建拉取请求”

  9. 等待检查完成,然后验证是否通过了所有检查,并且与 base 分支不会冲突。

    检查可能需要大约一分钟才能完成。 需要解决识别到的所有问题,然后才能将更改合并到 main 分支。

  10. 若要将更改合并到 main 分支,请选择“合并拉取请求”,然后选择“确认合并”

    请注意,合并更改后,可以删除 book-availability 分支。

  11. 打开 Visual Studio Code。

  12. 切换到存储库的 main 分支

  13. 从远程存储库拉取更改

  14. 验证你在 book-availability 分支中所做的更改现在是否已反映在 main 分支中