嗔秤戻幣�哉膵�云利匈嬉蝕湊蛸賜�塋床四衲���萩晦編報炎嘔囚^泡仟 ̄云利匈��
源平慎弌傍利 卦指云慕朕村 紗秘慕禰 厘議慕尺 厘議慕禰 TXT畠云和墮 〆辺茄欺厘議箝誓匂〇

VB2008貫秘壇欺娼宥(PDF鯉塀哂猟井)-及53何蛍

酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何! 泌惚云慕短嗤堋響頼���誅卒亮茂�俊彭堋響��辛聞喘貧圭 "辺茄欺厘議箝誓匂" 孔嬬 才 "紗秘慕禰" 孔嬬��



ticket。  



Converting a Binary Stream into a Text Stream 



Converting a binary stream into a text stream involves using the ´provided formatter to  

create a Ticket instance that is then converted into text。 The following is the plete source  

code ��you¨ll need a reference to  LottoLibrary in  Binary2Text��。 



Imports System。IO 

Imports System。Runtime。Serialization。Formatters。Binary 



Public Class LottoTicketProcessor �此�Implements IBinary2TextProcessor 

    Public Sub Process��ByVal input As Stream�察�ByVal output As TextWriter�� _ 

      Implements IBinary2TextProcessor。Process 

        Dim builder As StringBuilder = New StringBuilder�┌� 

        Try  

            Do While True 

                Dim formatter As BinaryFormatter = New BinaryFormatter�┌� 



                Dim ticket As LottoLibrary。Ticket = _ 

                    DirectCast��formatter。Deserialize��input���察�

                               LottoLibrary。Ticket�� 


´´´´´´´´´´´´´´´´´´´´´´Page 298´´´´´´´´´´´´´´´´´´´´´´´

276       CH AP T E R   1 0   *    L E A R N I N G   A B OU T   P E R S IS TE N CE 



                           builder。AppendFormat�─�_ 

                               ;��0��。��1��。��2�� ��3�� ��4�� ��5�� ��6�� ��7�� ��8�� ��9�� ��10��;�察�

                               ticket。DrawDate。Year�察�

                               ticket。DrawDate。Month�察�

                               ticket。DrawDate。Day�察�

                               ticket。Numbers��0���察�

                               ticket。Numbers��1���察�

                               ticket。Numbers��2���察�

                               ticket。Numbers��3���察�

                               ticket。Numbers��4���察�

                               ticket。Numbers��5���察�

                               ticket。Bonus�察�

                               ControlChars。NewLine�� 

                       Loop 

                   Catch e As Exception 

                   End Try 

                   output。Write��builder。ToString�┌��� 

               End Sub 

           End Class 



                In the code�察�a binary stream is read using the BinaryFormatter class�察�which reads the data  

           for an object from the data stream。 Notice how the method Deserialize�┌� does not ask which  

           type to read。 This is because all of that information is saved in the stream。 Deserialize�┌� will  

           read data from the stream�察�associate the data with a type�察�instantiate it�察�and populate the data  

           members。  

                The bolded code in the preceding listing points out where deserialization bees tricky�察 �

           which centers around when to read what type。 A binary stream when processed by the  

           BinaryFormatter will read and write objects。 BinaryFormatter will instantiate whatever it encoun

           ters and assumes that the caller of BinaryFormatter knows which type is being manipulated。 If  

           the caller does not know this�察�an exception will occur because the type cast to the specific type  

           will fail。 

                The exception block is necessary because you don¨t know how many Ticket objects have  

           been saved�察�as the count has not been saved to the stream。  provides the Position and  

           Length properties to determine if any instances are left to be read�察�but those properties work  

           only with files。 If the binary stream being read is a console data stream�察�there is no length or  

           position。 Thus�察�the only real solution is to keep reading until you can¨t do so anymore and  

           assume processing is plete。 



                                            INTENTION AND IMPLEMENTATION 



             The fact that  Position and  Length have different behaviors depending on the implementation might seem  

             to break the contract of being able to separate intention from implementation。 It seems to break the po

             nent software paradigm because�察�as a developer�察�you do need to know about the stream implementation。 The  

             rule has not been broken�察�but been put on hold�察�because sometimes you are left with no other option。 A file  

             stream and console stream share many characteristics�察�but knowing the length is not one of them。 A programmer  

             could force the console stream to give back some value�察�but that would be incorrect。 The smarter approach�察 �

             and the one chosen by the  implementers�察�is to generate an exception。 


´´´´´´´´´´´´´´´´´´´´´´Page 299´´´´´´´´´´´´´´´´´´´´´´´

                                                        CH A PT E R   1 0   *    L E A R N I N G   A B O U T  P E R S IS T E N CE 277 



        The binary stream formatter can bee even pickier。 Look at Figure 10´8 again and notice how the  

   type information with version identifiers is stored in the stream。 Imagine the situation where you create an  

   assembly that saves some objects。 Then x years and n versions of the program later�察�you try to load the file。  

   You can¨t�察�because the version of the type does not exist。 It is smart for the binary formatter to not instantiate  

   a version of a type that does not exist�察�because otherwise there could be serialization failures。 



Tweaking Serialization 



When dealing with serialization�察�you may e across a particular text or binary format that  

will require some extra work。 Also�察�you may have some objects that you want to exclude from  

serialization。 



Performing Custom Serialization 



Sometimes I think there are as many file formats as there are grains of sand on a beach。 As just  

two examples�察�specializations of text formats are XML and JSON ��for JavaScript Object Notation�察 �

used in JavaScript for your web browser��。 In most cases�察�the default serializations will work。  

However�察�you may need to tweak a particular serialization。 

     Many serialization techniques allow custom serializations of a particular object。 The default  

serialization implies a certain marshaling。 For example�察�it might mean an integer will be marshaled  

as an integer in another representation ��in SQL Server�察�for example��。 Sometimes�察�however�察�you  

might want different representations in different streams。 In that case�察�you need to implement  

the marshaling of the data member yourself。 With most serialization platforms�察�it means imple

menting a particular interface。 

     Following is an example that performs a custom serialization for a  binary stream。 



Imports System。Runtime。Serialization 



 _ 

Class MyObject 

    Implements ISerializable 

    Private value As Integer 



    Public Sub New�┌� 

    End Sub 



    Public Sub New��ByVal info As SerializationInfo�察�

                   ByVal context As StreamingContext�� 

        value = Integer。Parse��CStr��info。GetValue�─�value;�察�GetType��String�������� 

    End Sub 



    Public Sub GetObjectData��ByVal info As SerializationInfo�察�

                             ByVal context As StreamingContext�� 

    Implements ISerializable。GetObjectData 

        info。AddValue�─�value;�察�value。ToString�┌��� 

    End Sub 

End Class 


´´´´´´´´´´´´´´´´´´´´´´Page 300´´´´´´´´´´´´´´´´´´´´´´´

278       CH AP T E R   1 0   *    L E A R N I N G   A B OU T   P E R S IS TE N CE 



                In the example�察�the interface System。Runtime。Serialization。ISerializable is implemented。  

           This means when BinaryFormatter serializes or deserializes MyObject�察�BinaryFormatter will not  

           manipulate the binary stream�察�but delegate the manipulation to MyObject。 With many serializa

           tion platforms�察�there is an explicit method�察�property�察�or flag to indicate whether MyObject is  

           being written to the stream or read from the stream。 In the case of binary serialization�察�when an  

           object is written to the stream�察�the GetObjectData�┌� method is called�察�and when the object is  

           being read from the stream�察�the constructor is called。 

                Serialization involves two directions�察�and a developer must implement both�察�in the same  

           way。 In the example�察�the AddValue�┌� method is called�察�indicating that the data member is written as  

           a string�察�and when reading�察�the value data member must be read as a string。 



           *Note  One of the biggest challenges with serialization is that each and every serialization platform seems  

           to have its own way of doing things。 Sometimes there will be mon methods and attributes�察�but other times  

           they will not exist。 A universal approach to serialization won¨t work。 You should avoid performing custom seri

           alization whenever possible。 Most serialization platforms are smart enough to know what to do with each data  

           member。 So the best approach is to let the platform figure things out。 



           Declaring a Data Member As Nonserializable 



           In the example of the Ticket type�察�all of the data members were serialized。 However�察�some

           times that is not desired。 Suppose an object that you want to serialize has a network connection  

           or some other data value that will not make any sense if the object is serialized and then dese

           rialized some time later。 When the object is serialized�察�the network connection will also be  

           serialized�察�which is not appropriate。 It is not appropriate to serialize a network connection  

           because that object is transient and applies only to the context of the object instance。  

                To mark a data member as nonserializable�察�attributes are often used�察�as in the following  

           example。 



            

           Class MyObject2 

                

               Private _networkIdentifier As Integer 

           End Class 



                In the example�察�_networkIdentifier will not be written or read from the data stream。  



           Separating Data Objects from Action Objects 



           Another approach is to develop a number of data objects whose only role is to be used in seri

           alization and data referencing。 Such an approach is useful when using binary serialization�察 �

           because you are then able to more effectively manage the version problem。 The following is an  

           example of how such an architecture would be realized。 


´´´´´´´´´´´´´´´´´´´´´´Page 301´´´´´´´´´´´´´´´´´´´´´´´

                                                        CH A PT E R   1 0   *    L E A R N I N G   A B O U T  P E R S IS T E N CE 279 



 

Class MyObject2 

End Class 



Class Doer 

    Private _object As MyObject2 

    Private _networkIdentifier As Integer 

End Class 



     The class Doer has no serialization attribute and will not be serialized�察�but it references  

MyObject2。 The network identifier data member has been moved from MyObject2 to Doer。 The  

result is that MyObject2 contains nothing that is transient。 



pleting Custom Types 



When writing custom types�察�two methods are often implemented�察�especially where objects are  

to be pared a lot�此 �Equals�┌� and GetHashCode�┌�。 These two methods are used by the   

library API when paring and manipulating instances in a list or a collection。 It just happened  

in this chapter¨s example that a list of string types did the right thing。 If TextProcessor had used  

the Ticket type�察�then the Equals�┌� method of the list used to find date duplicates would not have  

worked。 The default implementations of  Equals�┌� and GetHashCode�┌� are not implemented  

properly。 This is not the  API¨s fault。 Rather�察�it is a recognition that Microsoft cannot know  

the structure of an object and what is considered as making a type unique。 



Implementing GetHashCode�┌� 



The MSDN documentation for Object。GetHashCode defines the GetHashCode�┌� method as follows  

��http��//msdn2。microsoft。/en´us/library/system。object。gethashcode��VS。90��。aspx���此�



      The GetHashCode method can be overridden by a derived type。 Value types must over

      ride this  method to  provide  a  hash  function  that  is  appropriate  for that type  and to 

     provide a useful distribution in  a hash table。 For  best results�察�the hash code must be 

     based on the value of an instance field or property instead of a static field or property。  



      Objects used as a key in a Hashtable object must also override the GetHashCode method 

     because those objects must generate their own hash code。 If an object used as a key does 

      not  provide  a  useful  implementation  of  GetHashCode�察 �you  can  specify  a  hash  code 

     provider when the Hashtable object is constructed。 



     But what does this actually mean�拭�The purpose of GetHashCode�┌� is to identify the object in  

a collection of other objects using a hash code。 Imagine creating a table of same´type instances。  

The situation occurs when you create a collection and store a bunch of instances in the collec

tion。 With the GetHashCode�┌� method�察�you can generally separate each instance from each other。  

I say ^generally ̄ because GetHashCode�┌� is an approximation。 To verify if one object instance  

equals another�察�the Equals�┌� method needs to be implemented。 


´´´´´´´´´´´´´´´´´´´´´´Page 302´´´´´´´´´´´´´´´´´´´´´´´

280       CH AP T E R   1 0   *    L E A R N I N G   A B OU T   P E R S IS TE N CE 



               Implementing a hash code is best delegated to a helper class that does the heavy lifting。  

          The book Effective Java Programming Language Guide by Joshua Bloch ��Prentice´Hall�察�2001��  

          outlines a robust technique。 Basically�察�you store some constant nonzero value�察�such as 17�察�in  

          a variable。 Then�察�for each data member of the type�察�perform a mathematical operation that  

          results in Integer values that are successively multiplied and added�察�where the operation is  

          specific to the type and defined as follows�此�



               o Boolean�此�If true return 0�察�otherwise return 1。 



               o Byte�察�Char�察�Short�察�or Integer�此�Return the value of the type。 



               o Long�此�Return CInt��value Xor ��value 〃〃 &H20����。 &H20 is the hexadecimal for 32。 



               o  Single�此�Return Convert。ToInt32 of the value。 



               o  Object�此�Return the value generated by calling Object。GetHashCode�┌�。 



               o Array �此�Iterate and treat each element individually。 



               The rules are implemented in a class called HashCodeAutomater。 The following source code  

          is an implementation in an abbreviated form�此�



          Public Class HashCodeAutomater 

              Private Readonly _constant As Integer 

              Private _runningTotal As Integer 



              Public Sub New�┌� 

                  _constant = &H25 

                  _runningTot
卦指朕村 貧匯匈 和匯匈 指欺競何 壘��16�� 家��13��
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何!
梁椣戻幣�� 梁心弌傍議揖扮窟燕得胎��傍竃徭失議心隈才凪万弌誌育断蛍�輌臆惨軼僑〃�燕慕得珊辛參資誼持蛍才将刮襲潜��範寔亟圻幹慕得 瓜寡追葎娼得辛參資誼寄楚署衛、持蛍才将刮襲潜填��