deep copy without using serialize/deserialize

Serialization and deserialization are popular when the object has enough properties that writing custom code would be time-consuming, but you can just write:

public static class BookExtensions
{
    public static Book Clone(this Book source)
    {
        return new Book {Chapter = source.Chapter, Page = source.Page};
    }
}

or make it a method of Book. Whether to do this or create an extension (above) is a matter of preference. If the method is in Book then you're more likely to remember to update the method if the class changes.

public class Book
{
    public string Chapter { get; set; }
    public int Page { get; set; }

    public Book Clone()
    {
        return new Book {Chapter = Chapter, Page = Page};
    }
}

(There's an ICloneable interface you can implement, but it's not popular. The Clone method returns object and you have to cast it.)

Another approach is to use a struct or record. You're likely cloning so that you can have an instance identical to another instance, but you can modify its properties without changing the first instance.

If you change your Book class to a struct, this test passes:

var book = new Book {Chapter = "x", Page = 1};
var book2 = book;
book2.Page = 2;
Assert.AreEqual(1, book.Page);

No need to clone anything.

Or you could create a record:

public record class Book(string chapter, int page)
{ }

and this test passes:

var book = new Book("x", 1);
var book2 = book with {page = 2};
Assert.AreEqual(1, book.page);

Each Book is immutable. You can pass it around to various methods and whenever a property needs to "change", a statement like var book2 = book with {page = 2}; creates a new book and only updates the specified property. No need to clone.