练习 - 使用 GitHub Copilot 工具重构和改进代码部分

已完成

GitHub Copilot 可以通过建议那些会提高代码的质量、可靠性、性能和安全性的更改来帮助你更新代码。

在本练习中,我们使用 GitHub Copilot 重构并改进以下代码部分:

  • 将 EnumHelper 类重构为使用字典,而不是反射。 使用字典可降低反射开销来提高性能。 消除反射还可以提高代码可读性、可维护性和安全性。

  • 重构数据访问方法以使用 LINQ(语言集成查询),而不是 foreach 循环。 使用 LINQ 可以更简洁、更易读地查询集合、数据库和 XML 文档。 使用 LINQ 可以提高代码可读性、可维护性和性能。

使用 GitHub Copilot 重构 EnumHelper 类

反射是一项强大的功能,可用于在运行时检查和操作对象。 但是,反射可能很慢,并且存在与应考虑的反射相关的潜在安全风险。

现有的 EnumHelper 类使用反射来检索枚举值的说明属性。 可以将 EnumHelper 类重构为使用字典,而不是反射。 使用字典可以提高性能,并消除与使用反射相关的任何安全问题。

在本练习中,你将使用 GitHub Copilot 来帮助重构 EnumHelper 类。

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

  1. 使用解决方案资源管理器视图打开 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. 打开“聊天”视图,然后将以下文件添加到聊天上下文:EnumHelper.csLoanExtensionStatus.csLoanReturnStatus.csMembershipRenewalStatus.cs

  3. 输入以下提示:

    @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.
    

    此提示要求 GitHub Copilot 提供有关如何更新 EnumHelper 类以使用字典而不是反射的说明。 它还要求更新的代码,代码使用每个枚举值的字典。

  4. 请花点时间查看 GitHub Copilot 提供的解释。

    解释应类似于以下说明:

    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.
    
    

    注意

    如果 GitHub Copilot 未使用正确的说明填充字典,请确保 GitHub Copilot 扩展不会请求重启。 如果是,请重启扩展,然后重试提示。

  5. 使用 GitHub Copilot 的建议 EnumHelper 类更新 EnumHelper.cs 文件。

  6. 确保已更新的 EnumHelper 类使用来自 LoanExtensionStatus.csLoanReturnStatus.csMembershipRenewalStatus.cs 文件的枚举值。

    打开每个枚举文件,并验证字典中的枚举值是否正确。 如果存在差异,请让 GitHub Copilot 分别更新每个枚举的字典。 例如,可以对 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.
    

    如有必要,对 LoanReturnStatusMembershipRenewalStatus 枚举使用相同的方法。

  7. 花点时间查看 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()
        };
    }
    

    此代码使用模式匹配来确定枚举的类型,并从相应的字典中检索说明。 switch 语句检查枚举 value 的类型,并从字典中返回相应的说明。 如果在字典中找不到枚举值,该方法将枚举值作为字符串返回。

    如果要求 GitHub Copilot 重构此代码并消除 lambda 表达式,则更易于阅读:

    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. 生成解决方案以确保不会出现错误。

    你将看到警告。 现在可以忽略这些文件。

更新数据访问方法以使用 LINQ

LINQ(语言集成查询)是 C# 中的一项强大功能,可用于以统一的方式查询集合、数据库和 XML 文档。 与传统的 foreach 循环相比,LINQ 提供了一种更简洁、更易读的方式来查询数据。

本练习的本部分包括以下任务:

  • 重构 JsonData.cs 中的方法来使用 LINQ。
  • 重构 JsonLoanRepository.cs 中的方法来使用 LINQ。
  • 重构 JsonPatronRepository.cs 中的方法来使用 LINQ。

重构 JsonData.cs 中的方法来使用 LINQ

JsonData 类包括以下数据访问方法:GetPopulatedPatron、GetPopulatedLoan、GetPopulatedBookItem、GetPopulatedBook。 这些方法使用 foreach 循环来循环访问集合并填充对象。 可以重构这些方法,以使用 LINQ 来提高代码可读性和可维护性。

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

  1. 打开 JsonData.cs 文件。

  2. 选择 GetPopulatedPatron 方法。

    GetPopulatedPatron 方法旨在创建完全填充的 Patron 对象。 它复制 Patron 的基本属性,并使用详细的 Loans 对象填充其 Loan 集合。

    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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    #selection refactor selection to `return new Patron` using LINQ
    
  4. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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()
        };
    }
    

    首先,LINQ 查询用于替换 foreach (Loan loan in Loans!) 循环。 有了 LINQ 代码,可以使用对象初始值设定项将对象属性分配给新的 Patron 对象。 这可以缓解对 populated 对象的单独 Patron 实例的需求。 总的来说,更新的代码更短且更易于阅读。

    该代码使用输入借阅者 p 将一些基本属性分配给新的 Patron 对象。 然后,它使用与输入借阅者关联的借阅填充 Loans 集合,并使用 GetPopulatedLoan 方法转换每个借阅。

    可以分解填充 Loans 集合的 LINQ 代码行:

    • Loans!Loans! 表达式访问 Loans 集合。 ! 运算符是一个 null 包容运算符,表示开发人员确信 Loans 不为 null。 在调用 Loans 方法之前,应确保正确初始化 GetPopulatedPatron
    • .Where(loan => loan.PatronId == p.Id):此代码筛选贷款,仅包含属于输入借阅者 p 的借阅。
    • .Select(GetPopulatedLoan):此代码使用 GetPopulatedLoan 方法转换每个筛选的借阅。
    • .ToList():将结果转换为 List<Loan>
  5. 若要接受建议的更新,请选择“接受”

    现在,你已了解如何重构 GetPopulatedPatron 方法,也可以重构 GetPopulatedLoanGetPopulatedBookItemGetPopulatedBook 方法以使用 LINQ。

  6. 使用相同的方法重构 GetPopulatedLoanGetPopulatedBookItemGetPopulatedBook 方法。

    例如,使用以下提示重构三种方法:

    对于 GetPopulatedLoan 方法:

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

    对于 GetPopulatedBookItem 方法:

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

    对于 GetPopulatedBook 方法:

    #selection refactor selection to `return new Book` using LINQ. Use `Where` and `Select` for `Author` property. Use `First` author.
    
  7. 接受建议的更新后,花时间查看代码更改。

    更新的代码看起来应该类似于:

    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. 使用“说明”智能操作查看 LINQ 查询的说明。

    “说明”智能操作提供代码中使用的 LINQ 查询的详细说明。

    例如,可以使用GetPopulatedBook 方法上的“说明”智能操作,以查看用于填充 Author 对象的 Book 属性的 LINQ 查询的说明。

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

    “说明”智能操作提供用于填充 Author 对象的 Book 属性的 LINQ 查询的详细说明。

    例如,说明可能类似这样:

    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. 生成解决方案以确保不会出现错误。

    你将看到警告。 现在可以忽略这些文件。

重构 JsonLoanRepository.cs 中的方法来使用 LINQ

JsonLoanRepository 类包括 GetLoanUpdateLoan 数据访问方法。 你将重构这两种方法,将 foreach 循环替换为 LINQ,以提高代码可读性和可维护性。

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

  1. 打开 JsonLoanRepository.cs 文件。

  2. 选择 GetLoan 方法。

    GetLoan 方法旨在按其 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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    例如,输入以下提示:

    #selection refactor selection using LINQ with `_jsonData.Loans!. Use `Where`, `Select` and `GetPopulatedLoan` to return `FirstOrDefault`.
    
  4. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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;
    }
    

    更新的代码使用 LINQ 筛选借阅集合,以仅包含具有指定 ID 的借阅。 请注意,应将 loan 声明为可为 null(Loan? loan)。 然后,它使用 GetPopulatedLoan 方法转换借阅,并返回第一个结果。 如果未找到匹配的借阅,FirstOrDefault 返回 null。 然后,该方法返回此借阅对象,如果没有具有指定 id 的借阅,该对象可能为 null。 此方法可确保返回的借阅完全填充所有必要的相关数据,从而全面了解借阅记录。

    可以进一步简化此代码:

    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. 若要接受更新后的 GetLoan 方法,请选择“接受”。

  6. 选择 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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    例如,输入以下提示:

    #selection refactor selection using LINQ find an existing loan `_jsonData.Loans!. Replace existing loan.
    
  8. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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();
        }
    }
    

    更新的代码使用 LINQ 查找借阅集合中的现有借阅。 然后,它会使用新的借阅数据更新现有借阅。 然后,该方法保存更新后的借阅集合,并重新加载数据。 此方法可确保正确更新借阅数据,并将更改保存到数据存储。

    还可以添加代码,以确保在执行方法之前加载数据:

    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. 若要接受更新后的 UpdateLoan 方法,请选择“接受”。

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

    你将看到警告。 现在可以忽略这些文件。

重构 JsonPatronRepository.cs 中的方法来使用 LINQ

JsonPatronRepository 类包括 SearchPatronsGetPatronUpdatePatron 方法,并且非常适合优化。 你将重构这两种方法,将 foreach 循环替换为 LINQ,以提高代码可读性和可维护性。

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

  1. 打开 JsonPatronRepository.cs 文件。

  2. 选择 SearchPatrons 方法。

    SearchPatrons 方法旨在按名称搜索借阅者。

    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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    例如,输入以下提示:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Replace the loop with `Where`, `OrderBy`, and `GetPopulatedPatrons`.
    
  4. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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. 若要接受更新后的 SearchPatrons 方法,请选择“接受”。

  6. 选择 GetPatron 方法。

    GetPatron 方法旨在返回与指定 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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    例如,输入以下提示:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Use `Where`, `Select` and `GetPopulatedPatron` to return `FirstOrDefault`
    
  8. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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;
    }
    

    可以进一步简化此代码:

    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. 若要接受更新后的 GetPatron 方法,请选择“接受”。

  10. 选择 UpdatePatron 方法。

    UpdatePatron 方法旨在更新具有指定 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. 打开内联聊天,然后使用 LINQ 输入重构方法的提示。

    例如,输入以下提示:

    #selection refactor selection using LINQ to find `patron` in `_jsonData.Patrons!. Replace existing patron with `patron`.
    
  12. 请花点时间来查看建议的更新。

    建议的更新看起来应类似于以下代码:

    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. 若要接受更新后的 UpdatePatron 方法,请选择“接受”。

检查你的工作

使用以下步骤检查工作:

  1. 若要清理解决方案,请右键单击 AccelerateAppDevGitHubCopilot,然后选择“清理”

    此操作从上一个生成中删除任何生成项目。 清理解决方案会有效地将 JSON 数据文件重置为其原始值(在输出目录中)。

  2. 生成应用程序,并确保没有任何错误。

  3. 运行该应用程序。

    可以通过右键单击 Library.Console 项目、选择“调试”,然后选择“启动新实例”,从解决方案资源管理器视图中运行应用程序。

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

  5. 在“匹配借阅者”提示处键入 2,然后按 Enter

  6. 在“图书借阅”提示处键入 1,然后按 Enter

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

  8. 确认是否显示“书籍已成功归还。”的消息。

  9. 若要开始新的搜索,请键入 s,然后按 Enter

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

  11. 在“匹配借阅者”提示处键入 2,然后按 Enter

  12. 确认第一本书籍的借阅记录是否标记为 Returned: True

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

  14. 停止应用程序。