Ejercicio: Refactorización y mejora de las secciones de código mediante las herramientas de GitHub Copilot

Completado

GitHub Copilot puede ayudarle a actualizar el código sugiriendo cambios que mejoran la calidad, confiabilidad, rendimiento y seguridad del código.

En este ejercicio, usará GitHub Copilot para refactorizar y mejorar las secciones de código siguientes:

  • Refactoriza la clase EnumHelper para usar diccionarios en lugar de reflexión. El uso de diccionarios mejora el rendimiento al reducir la sobrecarga de reflexión. La eliminación de la reflexión también mejora la legibilidad, el mantenimiento y la seguridad del código.

  • Los métodos de acceso a datos se refactorizarán para usar LINQ (Language Integrated Query) en lugar de bucles foreach. El uso de LINQ proporciona una manera más concisa y legible de consultar colecciones, bases de datos y documentos XML. El uso de LINQ puede mejorar la legibilidad, el mantenimiento y el rendimiento del código.

Uso de GitHub Copilot para refactorizar la clase EnumHelper

La reflexión es una característica eficaz que permite inspeccionar y manipular objetos en tiempo de ejecución. Sin embargo, la reflexión puede ser lenta y hay posibles riesgos de seguridad asociados a la reflexión que se deben tener en cuenta.

La clase EnumHelper existente usa la reflexión para recuperar el atributo descripción de un valor de enumeración. Puede refactorizar la clase EnumHelper para usar diccionarios en lugar de reflexión. El uso de diccionarios puede mejorar el rendimiento y eliminar cualquier problema de seguridad asociado al uso de la reflexión.

En este ejercicio, usará GitHub Copilot para ayudarle a refactorizar la clase EnumHelper.

Completa los siguientes pasos para usar esta sección del ejercicio:

  1. Use la vista Explorador de soluciones para abrir el archivo 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. Abra la vista Chat y agregue los siguientes archivos al contexto chat: EnumHelper.cs, LoanExtensionStatus.cs, LoanReturnStatus.cs, MembershipRenewalStatus.cs.

  3. Escriba lo siguiente:

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

    Este mensaje pide a GitHub Copilot que proporcione una explicación de cómo actualizar la clase EnumHelper para usar diccionarios en lugar de reflexión. También solicita el código actualizado que usa diccionarios para cada valor de enumeración.

  4. Dedique un minuto a revisar la explicación proporcionada por GitHub Copilot.

    La explicación debe ser similar a la siguiente descripción:

    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.
    
    

    Nota:

    Si GitHub Copilot no rellena los diccionarios con las descripciones correctas, asegúrese de que la extensión de GitHub Copilot no solicite un reinicio. Si es así, reinicie la extensión e inténtelo de nuevo.

  5. Use la clase EnumHelper sugerida de GitHub Copilot para actualizar el archivo EnumHelper.cs.

  6. Asegúrese de que la clase EnumHelper actualizada usa los valores de enumeración de los archivos LoanExtensionStatus.cs, LoanReturnStatus.cs y MembershipRenewalStatus.cs.

    Abra cada uno de los archivos de enumeración y compruebe que los valores de enumeración de los diccionarios son correctos. Si hay discrepancias, haga que GitHub Copilot actualice los diccionarios de cada enumeración individualmente. Por ejemplo, puede usar la siguiente solicitud para la enumeración 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.
    

    Si es necesario, use el mismo enfoque para las enumeraciones LoanReturnStatus y MembershipRenewalStatus.

  7. Dedique un minuto a revisar el método 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()
        };
    }
    

    Este código usa la coincidencia de patrones para determinar el tipo de enumeración y recuperar la descripción del diccionario adecuado. La instrucción switch comprueba el tipo de enumeración value y devuelve la descripción correspondiente del diccionario. Si el valor de enumeración no se encuentra en el diccionario, el método devuelve el valor de enumeración como una cadena.

    Si pide a GitHub Copilot que refactorice este código y elimine las expresiones lambda, resulta más fácil de leer:

    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. Compile la solución para asegurarse de que no hay errores.

    Verá advertencias. Puede ignorarlos por ahora.

Actualización de los métodos de acceso a datos para usar LINQ

LINQ (Language Integrated Query) es una característica eficaz en C# que permite consultar colecciones, bases de datos y documentos XML de forma uniforme. LINQ proporciona una manera más concisa y legible de consultar datos en comparación con los bucles foreach tradicionales.

En esta sección del ejercicio se incluyen las siguientes tareas:

  • Refactorice los métodos de JsonData.cs para usar LINQ.
  • Refactorice los métodos de JsonLoanRepository.cs para usar LINQ.
  • Refactorice los métodos de JsonPatronRepository.cs para usar LINQ.

Refactorización de los métodos de JsonData.cs para usar LINQ

La clase JsonData incluye los siguientes métodos de acceso a datos: GetPopulatedPatron, GetPopulatedLoan, GetPopulatedBookItem, GetPopulatedBook. Estos métodos usan bucles foreach para recorrer en iteración las colecciones y rellenar objetos. Puede refactorizar estos métodos para usar LINQ para mejorar la legibilidad y el mantenimiento del código.

Completa los siguientes pasos para usar esta sección del ejercicio:

  1. Abra el archivo JsonData.cs.

  2. Seleccione el método GetPopulatedPatron.

    El método GetPopulatedPatron está diseñado para crear un objeto Patron completamente rellenado. Copia las propiedades básicas del Patron y rellena su colección Loans con objetos Loan detallados.

    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. Abra un chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    #selection refactor selection to `return new Patron` using LINQ
    
  4. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

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

    En primer lugar, se usa una consulta LINQ para reemplazar el bucle foreach (Loan loan in Loans!). Con el código LINQ implementado, puede usar un inicializador de objeto para asignar propiedades de objeto al nuevo objeto Patron. Esto alivia la necesidad de una instancia de populated independiente del objeto Patron. En general, el código actualizado es más corto y legible.

    El código usa el patrón de entrada p para asignar algunas propiedades básicas al nuevo objeto Patron. A continuación, rellena la Loans colección con préstamos asociados con el patrón de entrada, transformando cada préstamo mediante el método GetPopulatedLoan.

    Puede desglosar la línea de código LINQ que rellena la colección Loans:

    • Loans!: La expresión Loans! accede a la colección Loans. El operador ! es un operador que admite valores null, lo que indica que el desarrollador está seguro de que Loans no es null. Debe asegurarse de que Loans se inicialice correctamente antes de llamar al método GetPopulatedPatron.
    • .Where(loan => loan.PatronId == p.Id): Este código filtra los préstamos para incluir solo los que pertenecen al patrón de entrada p.
    • .Select(GetPopulatedLoan): Este código transforma cada préstamo filtrado mediante el método GetPopulatedLoan.
    • .ToList(): Convierte el resultado en un List<Loan>.
  5. Para aceptar la actualización sugerida, seleccione Aceptar.

    Ahora que ha visto cómo refactorizar el método GetPopulatedPatron, también puede refactorizar los métodos GetPopulatedLoan, GetPopulatedBookItem, y GetPopulatedBook para usar LINQ.

  6. Refactorice los métodos GetPopulatedLoan, GetPopulatedBookItem, y GetPopulatedBook mediante el mismo enfoque.

    Por ejemplo, use las siguientes indicaciones para refactorizar los tres métodos:

    Para el método GetPopulatedLoan:

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

    Para el método GetPopulatedBookItem:

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

    Para el método GetPopulatedBook:

    #selection refactor selection to `return new Book` using LINQ. Use `Where` and `Select` for `Author` property. Use `First` author.
    
  7. Después de aceptar las actualizaciones sugeridas, dedique un minuto a revisar los cambios del código.

    El código actualizado debe tener un aspecto similar al siguiente:

    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. Use la acción inteligente Explicar para ver una explicación de las consultas LINQ.

    La acción inteligente Explicarproporciona una explicación detallada de las consultas LINQ usadas en el código.

    Por ejemplo, puede usar la acción inteligente Explicar en el método GetPopulatedBook para ver una explicación de la consulta LINQ que se usa para rellenar la propiedad Author del objeto Book.

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

    La acción inteligente Explicar proporciona una explicación detallada de la consulta LINQ que se usa para rellenar la Author propiedad del objetoBook.

    Por ejemplo, la explicación podría tener este aspecto:

    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. Compile la solución para asegurarse de que no hay errores.

    Verá advertencias. Puede ignorarlos por ahora.

Refactorización de los métodos de JsonLoanRepository.cs para usar LINQ

La clase JsonLoanRepository incluye los métodos de acceso a datos GetLoan y UpdateLoan. Refactorizará estos dos métodos, reemplazando los bucles foreach por LINQ para mejorar la legibilidad y el mantenimiento del código.

Completa los siguientes pasos para usar esta sección del ejercicio:

  1. Abra el archivo JsonLoanRepository.cs .

  2. Seleccione el método GetLoan.

    El método GetLoan está diseñado para recuperar un préstamo por su identificador.

    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. Abra el chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    Por ejemplo, escriba el siguiente símbolo del sistema:

    #selection refactor selection using LINQ with `_jsonData.Loans!. Use `Where`, `Select` and `GetPopulatedLoan` to return `FirstOrDefault`.
    
  4. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

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

    El código actualizado usa LINQ para filtrar la colección de préstamos para incluir solo el préstamo con el identificador especificado. Tenga en cuenta que loan debe declararse como que acepta valores NULL (Loan? loan). A continuación, transforma el préstamo mediante el método GetPopulatedLoan y devuelve el primer resultado. Si no se encuentra ningún préstamo coincidente, FirstOrDefault devuelve null. A continuación, el método devuelve este objeto de préstamo, que puede ser nulo si no existe ningún préstamo con el id especificado. Este enfoque garantiza que el préstamo devuelto se rellene completamente con todos los datos relacionados necesarios, lo que proporciona una visión completa del registro del préstamo.

    Este código podría simplificarse aún más:

    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. Para aceptar el método GetLoan actualizado, selecciona Aceptar.

  6. Seleccione el método 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. Abra el chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    Por ejemplo, escriba el siguiente símbolo del sistema:

    #selection refactor selection using LINQ find an existing loan `_jsonData.Loans!. Replace existing loan.
    
  8. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

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

    El código actualizado usa LINQ para encontrar el préstamo existente en la colección de préstamos. A continuación, actualiza el préstamo existente con los nuevos datos del préstamo. A continuación, el método guarda la colección de préstamos actualizados y vuelve a cargar los datos. Este enfoque garantiza que los datos del préstamo se actualicen correctamente y que los cambios se conserven en el almacén de datos.

    También puede agregar el código para asegurarse de que los datos se cargan antes de ejecutar el método:

    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. Para aceptar el método UpdateLoan actualizado, selecciona Aceptar.

  10. Compile la solución para asegurarse de que no hay errores.

    Verá advertencias. Puede ignorarlos por ahora.

Refactorización de los métodos en JsonPatronRepository para usar LINQ

La clase JsonPatronRepository incluye los métodos SearchPatrons, GetPatron, y UpdatePatron, y es un excelente candidato para la optimización. Refactorizará estos métodos y reemplazará los bucles foreach por LINQ para mejorar la legibilidad y el mantenimiento del código.

Completa los siguientes pasos para usar esta sección del ejercicio:

  1. Abra el archivo JsonPatronRepository.cs .

  2. Seleccione el método SearchPatrons.

    El método SearchPatrons está diseñado para buscar clientes por nombre.

    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. Abra el chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    Por ejemplo, escriba el siguiente símbolo del sistema:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Replace the loop with `Where`, `OrderBy`, and `GetPopulatedPatrons`.
    
  4. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

    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. Para aceptar el método SearchPatrons actualizado, selecciona Aceptar.

  6. Seleccione el método GetPatron.

    El método GetPatron está diseñado para devolver el patrón que coincide con el idespecificado.

    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. Abra el chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    Por ejemplo, escriba el siguiente símbolo del sistema:

    #selection refactor selection using LINQ with `_jsonData.Patrons!. Use `Where`, `Select` and `GetPopulatedPatron` to return `FirstOrDefault`
    
  8. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

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

    Este código podría simplificarse aún más:

    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. Para aceptar el método GetPatron actualizado, selecciona Aceptar.

  10. Seleccione el método UpdatePatron.

    El método UpdatePatron está diseñado para actualizar el patrón con el idespecificado.

    
    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. Abra el chat en línea y escriba un símbolo del sistema que refactorice el método mediante LINQ.

    Por ejemplo, escriba el siguiente símbolo del sistema:

    #selection refactor selection using LINQ to find `patron` in `_jsonData.Patrons!. Replace existing patron with `patron`.
    
  12. Dedique un minuto a revisar la actualización sugerida.

    La actualización sugerida debe ser similar al código siguiente:

    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. Para aceptar el método UpdatePatron actualizado, selecciona Aceptar.

Comprobación del trabajo

Siga estos pasos para comprobar el trabajo:

  1. Para limpiar la solución, haga clic con el botón derecho en AccelerateAppDevGitHubCopilot, y seleccione Limpiar.

    Esta acción quita los artefactos de compilación de la compilación anterior. La limpieza de la solución restablecerá eficazmente los archivos de datos JSON a sus valores originales durante (en el directorio de salida).

  2. Compile la aplicación y asegúrese de que no hay errores.

  3. Ejecute la aplicación.

    Para ejecutar la aplicación desde la vista Explorador de soluciones, haga clic con el botón derecho en el proyecto de Library.Console, seleccione Depurar y, a continuación, seleccione Iniciar nueva instancia.

  4. Cuando se le solicite un nombre de patrón, escriba One y presione Entrar.

  5. En el símbolo del sistema "Patrones coincidentes", escriba 2 y presione Entrar.

  6. En el símbolo del sistema "Reservar préstamos", escriba 1 y presione Entrar.

  7. En el símbolo del sistema "Opciones de entrada", escriba r y presione Entrar.

  8. Compruebe que se muestra el mensaje "Book was successfully returned" (Libro devuelto correctamente).

  9. Para iniciar una nueva búsqueda, escriba s y presione Entrar.

  10. Cuando se le solicite un nombre de patrón, escriba One y presione Entrar.

  11. En el símbolo del sistema "Patrones coincidentes", escriba 2 y presione Entrar.

  12. Compruebe que el primer préstamo de libros está marcado Returned: True.

  13. En el símbolo del sistema "Opciones de entrada", escriba q y presione Entrar.

  14. Detenga la aplicación.