Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 82 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
82
Dung lượng
419,01 KB
Nội dung
132 Chapter Searching, Modifying, and Encoding Text C Encoding.UTF8 D Encoding.UTF7 You are writing an application that generates summary reports nightly These reports will be viewed by executives in your Korea office and must contain Korean characters Which of the following encoding types is the best one to use? A iso-2022-kr B x-EBCDIC-KoreanExtended C x-mac-korean D UTF-16 Chapter Review 133 Chapter Review To practice and reinforce the skills you learned in this chapter further, you can perform the following tasks: Review the chapter summary Review the list of key terms introduced in this chapter Complete the case scenarios These scenarios set up real-world situations involving the topics of this chapter and ask you to create a solution Complete the suggested practices Take a practice test Chapter Summary Regular expressions have roots in UNIX and Perl, and they can seem complicated and unnatural to NET Framework developers However, regular expressions are extremely efficient and useful for validating text input, extracting text data, and reformatting data In the past decade, the most commonly used encoding standard for text files has gradually shifted from ASCII to Unicode Unicode itself supports several different encoding standards While the NET Framework uses the UTF-16 encoding standard by default, you can specify other encoding standards to meet interoperability requirements Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book Code page Regular expression Unicode Case Scenarios In the following case scenarios, you apply what you’ve learned about how to validate input using regular expressions and how to process text files with different encoding types You can find answers to these questions in the “Answers” section at the end of this book 134 Chapter Review Case Scenario 1: Validating Input Your organization, Northwind Traders, is creating a Web-based application to allow customers to enter their own contact information into your database As a new employee, you are assigned a simple task: create the front-end interface and prepare the user input to be stored in a database You begin by interviewing several company personnel and reviewing the technical requirements Interviews The following is a list of company personnel that you interviewed and their statements “This is your first assignment, so I’m starting you out easy Slap together a Web page that takes user input That should take you, what, five minutes?” IT Manager Database Developer “Just drop the input into strings named companyName, contactName”, and phoneNumber It’s going into a SQL back-end database, but I’ll write that code after you’re done Oh, the companyName can’t be longer than 40 characters, contactName is limited to 30 characters, and phoneNumber is limited to 24 characters.” “This is not as easy an assignment as it seems This page is going to be available to the general public on the Internet, and there are lots of black hats out there We’ve gotten some negative attention in the press recently for our international trade practices Specifically, we’ve irritated a couple of groups with close ties to hacker organizations Just your best to clean up the input, because you’re going to see some malicious junk thrown at you.” Chief Security Officer Technical Requirements Create an ASP.NET application that accepts the following pieces of information from users and validates it rigorously: Company name Contact name Phone number Questions Answer the following questions for your manager: How can you constrain the input before you write any code? How can you constrain the input further by writing code? Chapter Review 135 Case Scenario 2: Processing Data from a Legacy Computer You are an application developer working for Humongous Insurance Recently, management decided to begin the process of migrating from a legacy system (nicknamed “Mainframe”) to custom-built NET Framework applications As part of the kickoff meeting for the migration project, your manager asks you questions about how you will handle various challenges Questions Answer the following questions for your manager: “Mainframe” stores its data in a database; however, the raw data itself isn’t accessible to us unless we can find a programmer who knows how to write code for that system We can output the data we need in text-based reports, however Is it possible to parse the text reports to extract just the data, without the labels and formatting? How would you that, and which classes and methods would you use? “Mainframe's” reports are in ASCII format Can you handle that in ASCII? If so, how? Suggested Practices To help you master the exam objectives presented in this chapter, complete the following tasks Enhance the Text-Handling Capabilities of a NET Framework Application, and Search, Modify, and Control Text Within a NET Framework Application by Using Regular Expressions For this task, you should complete at least Practices through If you want a better understanding of how to specify encoding types, complete Practice as well Write a Console application that reads your C:\Boot.ini file and displays just the timeout Practice Write a Console application that processes your %Windir%\WindowsUpdate.log file and displays the time, date, and exit code for any rows that list an exit code Practice Write a Windows Forms application that accepts a name, address, and phone number from a user Add a Submit button that uses regular expressions to validate the input Practice 136 Chapter Review Write a Console application that reads the %Windir%\WindowsUpdate.log file, changes the date format to mm-dd-yy, and writes the output to a second file Practice Write a Console application with a method that reads the %windir%\WindowsUpdate.log file and writes the output to a second file using an encoding type provided in a parameter Compare the file sizes of each encoding type Practice Take a Practice Test The practice tests on this book’s companion CD offer many options For example, you can test yourself on just one exam objective, or you can test yourself on all the 70-536 certification exam content You can set up the test so that it closely simulates the experience of taking a certification exam, or you can set it up in study mode so that you can look at the correct answers and explanations after you answer each question MORE INFO Practice Tests For details about all the practice test options available, see the section “How to Use the Practice Tests” section in the Introduction of this book Chapter Collections and Generics Developers often need to store groups of related objects For example, an e-mail inbox would contain a group of messages, a phone book would contain a group of phone numbers, and an audio player would contain a group of songs The NET Framework provides the System.Collections namespace to allow developers to manage groups of objects Different collections exist to provide performance benefits in different scenarios, flexible sorting capabilities, support for different types, and dictionaries that pair keys and values Exam objectives in this chapter: Manage a group of associated data in a NET Framework application by using collections Improve type safety and application performance in a NET Framework application by using generic collections Manage data in a NET Framework application by using specialized collections Lessons in this chapter: Lesson 1: Collections and Dictionaries 138 Lesson 2: Generic Collections 150 Before You Begin This book assumes that you have at least two to three years of experience developing Web-based, Microsoft Windows–based, or distributed applications using the NET Framework Candidates should have a working knowledge of Microsoft Visual Studio Before you begin, you should be familiar with Microsoft Visual Basic or C# and be comfortable with the following tasks: Creating console and Windows Presentation Foundation (WPF) applications in Visual Studio using Visual Basic or C# Adding namespaces and system class library references to a project Running a project in Visual Studio, setting breakpoints, stepping through code, and watching the values of variables 137 138 Chapter Collections and Generics Lesson 1: Collections and Dictionaries The System.Collections and System.Collections.Specialized namespaces contain a number of classes to meet varying requirements for storing groups of related objects To use them most efficiently, you need to understand the benefits of each class This lesson describes each collection and dictionary type and shows you how to use them After this lesson, you will be able to: Use collections and choose the best collection class for different requirements Use dictionaries and choose the best dictionary class for different requirements Estimated lesson time: 30 minutes Collections A collection is any class that allows for gathering items into lists and for iterating through those items The NET Framework includes the following collection classes: ArrayList A simple collection that can store any type of object ArrayList instances expand to any required capacity Queue A first-in, first-out (FIFO) collection You might use a Queue on a messaging server to store messages temporarily before processing or to track customer orders that need to be processed on a first-come, first-serve basis Stack A last-in, first-out (LIFO) collection You might use a Stack to track changes so that the most recent change can be undone StringCollection Like ArrayList, except values are strongly typed as strings, and StringCollection does not support sorting BitArray A collection of boolean values ArrayList Use the ArrayList class (in the System.Collections namespace) to add objects that can be accessed directly using a zero-based index or accessed in a series using a foreach loop The capacity of an ArrayList expands as required The following example shows how to use the ArrayList.Add method to add different types of objects to a single array, and then access each object using a foreach loop: ' VB Dim al As New ArrayList() al.Add("Hello") al.Add("World") Lesson 1: Collections and Dictionaries 139 al.Add(5) al.Add(New FileStream("delemete", FileMode.Create)) Console.WriteLine("The array has " + al.Count.ToString + " items:") For Each s As Object In al Console.WriteLine(s.ToString()) Next // C# ArrayList al = new ArrayList(); al.Add("Hello"); al.Add("World"); al.Add(5); al.Add(new FileStream("delemete", FileMode.Create)); Console.WriteLine("The array has " + al.Count + " items:"); foreach (object s in al) Console.WriteLine(s.ToString()); This console application displays the following: The array has items: Hello World System.IO.FileStream In practice, you generally add items of a single type to an ArrayList This allows you to call the Sort method to sort the objects using their IComparable implementation You can also use the Remove method to remove an object you previously added and use the Insert method to add an element at the specified location in the zero-based index The following code sample demonstrates this: ' VB Dim al As New ArrayList() al.Add("Hello") al.Add("World") al.Add("this") al.Add("is") al.Add("a") al.Add("test") al.Remove("test") al.Insert(4, "not") al.Sort() For Each s As Object In al Console.WriteLine(s.ToString()) Next 140 Chapter Collections and Generics // C# ArrayList al = new ArrayList(); al.Add("Hello"); al.Add("World"); al.Add("this"); al.Add("is"); al.Add("a"); al.Add("test"); al.Remove("test"); al.Insert(4, "not"); al.Sort(); foreach (object s in al) Console.WriteLine(s.ToString()); This code sample results in the following display Notice that the items are sorted alphabetically (using the string IComparable implementation) and “test” has been removed: A Hello is not this World IMPORTANT Using StringCollection You could also use StringCollection in place of ArrayList in the previous example However, StringCollection does not support sorting, described next The primary advantage of StringCollection is that it’s strongly typed for string values You can also create your own custom IComparer implementations to control sort order While the IComparable.CompareTo method controls the default sort order for a class, IComparer.Compare can be used to provide custom sort orders For example, consider the following simple class, which only implements IComparer: ' VB Public Class reverseSort Implements IComparer Private Function Compare(ByVal x As Object, ByVal y As Object) _ As Integer Implements IComparer.Compare Return ((New CaseInsensitiveComparer()).Compare(y, x)) End Function End Class Lesson 1: Collections and Dictionaries 141 // C# public class reverseSort : IComparer { int IComparer.Compare(Object x, Object y) { return ((new CaseInsensitiveComparer()).Compare(y, x)); } } Given that class, you could pass an instance of the class to the ArrayList.Sort method The following code sample demonstrates this and also demonstrates using the ArrayList.AddRange method, which adds each element of an array as a separate element to the instance of ArrayList: ' VB Dim al As New ArrayList() al.AddRange(New String() {"Hello", "world", "this", "is", "a", "test"}) al.Sort(New reverseSort()) For Each s As Object In al Console.WriteLine(s.ToString()) Next // C# ArrayList al = new ArrayList(); al.AddRange(new string[] {"Hello", "world", "this", "is", "a", "test"}); al.Sort(new reverseSort()); foreach (object s in al) Console.WriteLine(s.ToString()); This code displays the following: world this test is Hello A You can also call the ArrayList.Reverse method to reverse the current order of items in the ArrayList To locate a specific element, call the ArrayList.BinarySearch method and pass an instance of the object you are searching for BinarySearch returns the zero-based index Lesson 2: XML Serialization 199 // Create file to save the data to FileStream fs = new FileStream("Person.XML", FileMode.Open); // Create an XmlSerializer object to perform the deserialization XmlSerializer xs = new XmlSerializer(typeof(Person)); // Use the XmlSerializer object to deserialize the data to the file dsp = (Person)xs.Deserialize(fs); // Close the file fs.Close(); return dsp; } Build the project and resolve any errors Open a command prompt to the build directory, and then run the following command: Serialize-People Tony 1923 22 What exception message you receive, and why? You see the message “Invalid parameters Serialize_People.Person is inaccessible due to its protection level Only public types can be processed.” The error occurs because the Person class is not marked as public Edit the Person class, and mark it as public Then rebuild the project, and run the following command again: Serialize-People Tony 1923 22 Examine the serialized data to verify that the information you provided on the command line was successfully captured Why does the age appear in the serialized file even though the age member has the NonSerialized attribute? The NonSerialized attribute applies to binary serialization, but it does not affect XML serialization Now run the command with no parameters to verify that deserialization works properly Lesson Summary XML serialization provides interoperability to communicate with different platforms and flexibility to conform to an XML schema XML serialization cannot be used to serialize private data or object graphs 200 Chapter Serialization To serialize an object, first create a stream, TextWriter, or XmlWriter Then create an XmlSerializer object and call the XmlSerializer.Serialize method To deserialize an object, follow the same steps but call the XmlSerializer.Deserialize method To create a class that can be serialized as XML, specify the class and all members as public and create a parameterless constructor You can control XML serialization by using attributes Attributes can change the names of elements, serialize members as XML attributes rather than as XML elements, and exclude members from serialization Use the Xsd.exe tool to create a class that automatically conforms to an XML schema when serialized Data sets, arrays, collections, and instances of an XmlElement or XmlNode class can all be serialized with XmlSerializer Lesson Review You can use the following questions to test your knowledge of the information in Lesson 2, “XML Serialization.” The questions are also available on the companion CD if you prefer to review them in electronic form NOTE Answers Answers to these questions and explanations of why each answer choice is right or wrong are located in the ”Answers” section at the end of the book Which of the following are requirements for a class to be serialized with XML serialization? (Choose all that apply.) A The class must be public B The class must be private C The class must have a parameterless constructor D The class must have a constructor that accepts a SerializationInfo parameter Which of the following attributes would you use to cause a member to be serialized as an XML attribute, rather than as an XML element? A XmlAnyAttribute B XmlType C XmlElement D XmlAttribute Lesson 2: XML Serialization 201 Which tool would you use to help you create a class that, when serialized, would produce an XML document that conformed to an XML schema? A Xsd.exe B Xdcmake.exe C XPadsi90.exe D Xcacls.exe Which of the following attributes should you add to a member to prevent it from being serialized by XML serialization? A XmlType B XmlIgnore C XmlElement D XmlAttribute 202 Chapter Serialization Lesson 3: Custom Serialization Custom serialization is the process of controlling the serialization and deserialization of a type By controlling serialization, it is possible to ensure serialization compatibility, which is the ability to serialize and deserialize between versions of a type without breaking the core functionality of the type For example, in the first version of a type, there might be only two fields In the next version of a type, several more fields are added Yet the second version of an application must be able to serialize and deserialize both types This lesson describes how to control serialization by implementing your own serialization classes After this lesson, you will be able to: Implement the ISerializable interface to take control over how a class is serialized Respond to serialization events to run code at different stages of the serialization process Write code that adjusts serialization and deserialization according to the context Describe the role of IFormatter Estimated lesson time: 30 minutes How to Implement Custom Serialization Serialization in the NET Framework is very flexible and can be customized to meet most development requirements In some circumstances, you might need complete control over the serialization process You can override the serialization built into the NET Framework by implementing the ISerializable interface and applying the Serializable attribute to the class This is particularly useful in cases where the value of a member variable is invalid after deserialization, but you need to provide the variable with a value to reconstruct the full state of the object In addition, you should not use default serialization on a class that is marked with the Serializable attribute and has declarative or imperative security at the class level or on its constructors Instead, these classes should always implement the ISerializable interface Implementing ISerializable involves implementing the GetObjectData method and a special constructor that is used when the object is deserialized The runtime calls GetObjectData during serialization, and the serialization constructor during deserialization The compiler warns you if you forget to implement GetObjectData, but if you forget to implement the special constructor, you won’t notice a problem until runtime when you receive a serialization exception Lesson 3: Custom Serialization 203 When the runtime calls GetObjectData during serialization, you are responsible for populating the SerializationInfo object that is provided with the method call Simply add the variables to be serialized as name/value pairs using the AddValue method, which internally creates SerializationEntry structures to store the information Any text can be used as the name You have the freedom to decide which member variables are added to the SerializationInfo object, provided that sufficient data is serialized to restore the object during deserialization When the runtime calls your serialization constructor, simply retrieve the values of the variables from SerializationInfo using the names used during serialization The following sample code, which uses the System.Runtime.Serialization and System Security.Permissions namespaces, shows how to implement ISerializable, the serialization constructor, and the GetObjectData method: ' VB Class ShoppingCartItem Implements ISerializable Public productId As Int32 Public price As Decimal Public quantity As Int32 Public total As Decimal ' The standard, non-serialization constructor Public Sub New(ByVal _productID As Integer, ByVal _price As Decimal, _ ByVal _quantity As Integer) MyBase.New() productId = _productID price = _price quantity = _quantity total = price * quantity End Sub ' The following constructor is for deserialization Protected Sub New(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) MyBase.New() productId = info.GetInt32("Product ID") price = info.GetDecimal("Price") quantity = info.GetInt32("Quantity") total = price * quantity End Sub ' The following method is called during serialization _ Public Overridable Sub GetObjectData(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) _ Implements System.Runtime.Serialization.ISerializable.GetObjectData 204 Chapter Serialization info.AddValue("Product ID", productId) info.AddValue("Price", price) info.AddValue("Quantity", quantity) End Sub Public Overrides Function ToString() As String Return productId + ": " + price + " x " + quantity + " = " + total End Function End Class // C# [Serializable] class ShoppingCartItem : ISerializable { public Int32 productId; public decimal price; public Int32 quantity; [NonSerialized] public decimal total; // The standard, non-serialization constructor public ShoppingCartItem(int _productID, decimal _price, int _quantity) { productId = _productID; price = _price; quantity = _quantity; total = price * quantity; } // The following constructor is for deserialization protected ShoppingCartItem(SerializationInfo info, StreamingContext context) { productId = info.GetInt32("Product ID"); price = info.GetDecimal("Price"); quantity = info.GetInt32("Quantity"); total = price * quantity; } // The following method is called during serialization [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Product ID", productId); info.AddValue("Price", price); info.AddValue("Quantity", quantity); } public override string ToString() { return productId + ": " + price + " x " + quantity + " = " + total; } } Lesson 3: Custom Serialization 205 In this example, SerializationInfo does much of the work of serialization and deserialization The construction of a SerializationInfo object requires an object whose type implements the IFormatterConverter interface BinaryFormatter and SoapFormatter always construct an instance of the System.Runtime.Serialization.FormatterConverter type, without giving you the opportunity to use a different IFormatterConverter type FormatterConverter includes methods for converting values between core types, such as converting a Decimal to a Double or a signed integer to an unsigned integer IMPORTANT Reducing Security Risks by Using Data Validation You must perform data validation in your serialization constructor and throw a SerializationException if invalid data is provided The risk is that an attacker could use your class but provide fake serialization information in an attempt to exploit a weakness You should assume that any calls made to your serialization constructor are initiated by an attacker, and allow the construction only if all the data provided is valid and realistic For more information about code security, refer to Chapter 12 Responding to Serialization Events The NET Framework supports binary serialization events when using the BinaryFormatter class Events are supported only for BinaryFormatter serialization For SoapFormatter or custom serialization, you are limited to using the IDeserializationCallback interface, as discussed in Lesson of this chapter These events call methods in your class when serialization and deserialization take place There are four serialization events: This event is raised just before serialization takes place Apply the OnSerializing attribute to the method that should run in response to this event Serializing This event is raised just after serialization takes place Apply the OnSerialized attribute to the method that should run in response to this event Serialized This event is raised just before deserialization takes place Apply the OnDeserializing attribute to the method that should run in response to this event Deserializing Deserialized This event is raised just after deserialization takes place and after IDeserializationCallback.OnDeserialization has been called You should use IDeserializationCallback.OnDeserialization instead when formatters other than BinaryFormatter might be used Apply the OnDeserialized attribute to the method that should run in response to this event 206 Chapter Serialization The sequence of these events is illustrated in Figure 5-1 Serialization begins Deserialization begins [OnSerializing] [OnDeserializing] Serialization occurs Deserialization occurs [OnSerialized] IDeserializationCallback, OnDeserialization Serialization completed [OnDeserialized] Deserialization completed Figure 5-1 You can use serialization events to run methods during different phases of the serialization and deserialization process Using these events is the best and easiest way to control the serialization process The methods not access the serialization stream but instead allow you to alter the object before and after serialization or before and after deserialization The attributes can be applied at all levels of the type inheritance hierarchy, and each method is called in the hierarchy from the base to the most derived This mechanism avoids the complexity and any resulting issues of implementing the ISerializable interface by giving the responsibility for serialization and deserialization to the most derived implementation For a method to respond to one of these events, the method must meet the following requirements: Accept a StreamingContext object as a parameter Return void Have the attribute that matches the event you want to intercept The following example demonstrates how to create an object that responds to serialization events In your own code, you can respond to as many or as few events as you Lesson 3: Custom Serialization 207 want In addition, you can apply the same serialization event to multiple methods or apply multiple events to a single method: ' VB Class ShoppingCartItem Public productId As Int32 Public price As Decimal Public quantity As Int32 Public total As Decimal _ Private Sub CalculateTotal(ByVal sc As StreamingContext) total = price * quantity End Sub _ Private Sub CheckTotal(ByVal sc As StreamingContext) If (total = 0) Then CalculateTotal(sc) End If End Sub End Class // C# [Serializable] class ShoppingCartItem { public Int32 productId; public decimal price; public Int32 quantity; public decimal total; [OnSerializing] void CalculateTotal(StreamingContext sc) { total = price * quantity; } [OnDeserialized] void CheckTotal(StreamingContext sc) { if (total == 0) { CalculateTotal(sc); } } } How to Change Serialization Based on Context Typically, when you serialize an object, the destination does not matter In some circumstances, however, you might want to serialize and deserialize an object differently depending on the destination For example, you typically should not serialize members 208 Chapter Serialization that contain information about the current process because that information might be invalid when the object is deserialized However, that information would be useful if the object is going to be deserialized by the same process Alternatively, if the object is useful only if deserialized by the same process, you might choose to throw an exception if you knew the destination was a different process The StreamingContext structure can provide information about the destination of a serialized object to classes that implement the ISerializable interface StreamingContext is passed to both GetObjectData and an object’s serialization constructor The StreamingContext structure has two properties: A reference to an object that contains any user-desired context information Context A set of bit flags indicating the source or destination of the object being serialized/deserialized The flags are the following: State CrossProcess The source or destination is a different process on the same machine CrossMachine The source or destination is on a different machine File The source or destination is a file Don’t assume that the same process will deserialize the data The source or destination is a store such as a database, file, or other Don’t assume that the same process will deserialize the data Persistence Remoting The source or destination is remoting to an unknown location The location might be on the same machine but might also be on another machine Other The source or destination is unknown The object graph is being cloned The serialization code might assume that the same process will deserialize the data and it is therefore safe to access handles or other unmanaged resources Clone CrossAppDomain The source or destination is a different AppDomain All The source or destination might be any of the above contexts This is the default context To make context decisions during serialization and deserialization, implement the ISerializable interface in your class For serialization, inspect the StreamingContext structure passed to your object’s GetObjectData method For deserialization, inspect the StreamingContext structure passed to your object’s serialization constructor Lesson 3: Custom Serialization 209 If you are serializing or deserializing an object and want to provide context information, modify the StreamingContext object returned by the IFormatter.Context property before calling the formatter’s Serialize or Deserialize methods This property is implemented by both the BinaryFormatter and SoapFormatter classes When you construct a formatter, the formatter automatically sets the Context property to null and the State property to All How to Create a Custom Formatter To create a custom formatter, implement the IFormatter interface Both BinaryFormatter and SoapFormatter implement the IFormatter interface The FormatterServices class provides static methods (including GetObjectData) to aid with the implementation of a formatter MORE INFO Custom Formatters Very few people need to implement custom formatters Therefore, this book covers them at a very high level For detailed information about custom formatters, read ”Format Your Way to Success with the NET Framework Versions 1.1 and 2.0” at http://msdn.microsoft.com/en-us /magazine/cc163902.aspx and ”Run-time Serialization” at http://msdn.microsoft.com/en-us/library /cc301761.aspx Also, read ”Writing Simple Custom Formatter” at http://geekswithblogs.net/luskan /archive/2007/07/16/113956.aspx Lab: Implement Custom Serialization In this lab, you will modify a class to override the default serialization and take control over which members are serialized If you encounter a problem completing an exercise, the completed projects are available along with the sample files Exercise: Update a Class to Use Custom Serialization In this exercise, you will update a class to improve the efficiency of serialization while maintaining complete control over how data is stored and retrieved Navigate to the \\Chapter05\Lesson3\Exercise1\Partial folder and open either the C# version or the Visual Basic NET version of the solution file Add the System.Runtime.Serialization namespace to the Person class Add the Serializable attribute to the Person class, and then build the project to ensure it compiles correctly Modify the Person class so that it implements ISerializable 210 Chapter Serialization Add the GetObjectData method, which accepts a SerializationInfo object and a StreamingContext object and adds items to be serialized to the SerializationInfo object Add the name and dateOfBirth variables to the SerializationInfo object, but not add the age variable Your code could look like the following: ' VB Public Overridable Sub GetObjectData(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) _ Implements System.Runtime.Serialization.ISerializable.GetObjectData info.AddValue("Name", name) info.AddValue("DOB", dateOfBirth) End Sub // C# public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Name", name); info.AddValue("DOB", dateOfBirth); } Add the serialization constructor, which accepts a SerializationInfo object and a StreamingContext object and then initializes member variables using the contents of the SerializationInfo object Use the same element names you used in the previous step After you have deserialized all variables, call the CalculateAge method to initialize the age variable Your code could look like the following: ' VB Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) name = info.GetString("Name") dateOfBirth = info.GetDateTime("DOB") CalculateAge End Sub // C# public Person(SerializationInfo info, StreamingContext context) { name = info.GetString("Name"); dateOfBirth = info.GetDateTime("DOB"); CalculateAge(); } Build the project and resolve any errors Open a command prompt to the build directory, and then run the following command: Serialize-People Tony 1923 22 Now run the command with no parameters to verify that deserialization works properly Lesson 3: Custom Serialization 211 Lesson Summary You can implement ISerializable to perform custom serialization BinaryFormatter provides four events that you can use to control parts of the serialization process: OnSerializing, OnSerialized, OnDeserializing, and OnDeserialized The StreamingContext class, an instance of which is provided to methods called during serialization events, gives you information about the origin or planned destination of the serialization process The method performing serialization must specify this information for it to be useful Although few developers require total control over serialization, you can implement the IFormatter interface to create custom formatters Lesson Review You can use the following questions to test your knowledge of the information in Lesson 3, “Custom Serialization.” The questions are also available on the companion CD if you prefer to review them in electronic form NOTE Answers Answers to these questions and explanations of why each answer choice is right or wrong are located in the ”Answers” section at the end of the book Which parameters must a constructor accept if the class implements ISerializable? (Choose all that apply.) A SerializationInfo B Formatter C StreamingContext D ObjectManager Which event would you use to run a method immediately before deserialization occurs? A OnSerializing B OnDeserializing C OnSerialized D OnDeserialized 212 Chapter Serialization Which event would you use to run a method immediately after serialization occurs? A OnSerializing B OnDeserializing C OnSerialized D OnDeserialized Which of the following are requirements for a method that is called in response to a serialization event? (Choose all that apply.) A Accept a StreamingContext object as a parameter B Accept a SerializationInfo object as a parameter C Return void D Return a StreamingContext object Chapter Review 213 Chapter Review To practice and reinforce the skills you learned in this chapter further, you can any of the following tasks: Review the chapter summary Review the list of key terms introduced in this chapter Complete the case scenarios These scenarios set up real-world situations involving the topics of this chapter and ask you to create a solution Complete the suggested practices Take a practice test Chapter Summary Serialization outputs an object as a series of bytes, whereas deserialization reads a serialized object and defines the value of an object Most custom classes can be serialized by simply adding the Serializable attribute In some cases, you might be able to improve efficiency or provide for changes to the structure of classes by modifying your class to change the default serialization behavior XML serialization provides a way to store and transfer objects using open standards XML serialization can be customized to fit the exact requirements of an XML schema, making it simple to convert objects into XML documents and back into objects Custom serialization is required in situations where classes contain complex information, significant changes have occurred to the structure of a class between different versions, or where you need complete control over how information is stored You can perform custom serialization by implementing the ISerializable interface and by responding to serialization events Key Terms Do you know what these key terms mean? You can check your answers by looking up the terms in the glossary at the end of the book BinaryFormatter Extensible Markup Language (XML) Deserialization Serialization SoapFormatter ... values Exam objectives in this chapter: Manage a group of associated data in a NET Framework application by using collections Improve type safety and application performance in a NET Framework application. .. book’s companion CD offer many options For example, you can test yourself on just one exam objective, or you can test yourself on all the 70- 536 certification exam content You can set up the test so... companion CD offer many options For example, you can test yourself on just the content covered in this chapter, or you can test yourself on all the 70- 536 certification exam content You can set up the