演练:保持对象(C# 和 Visual Basic)

虽然您可以在设计时将对象的属性设置为默认值,但是,如果该对象被损环,则在运行时输入的所有值均会丢失。 可以使用序列化在实例之间保持对象数据,从而能够存储值并且在下次实例化对象时检索这些值。

提示

在 Visual Basic 中,若要存储简单数据(例如名称或数字),可以使用 My.Settings 对象。 有关更多信息,请参见 My.Settings 对象 (Visual Basic)

在本演练中,将创建一个简单的 Loan 对象,并将该对象的数据保存到文件中。 然后,当您重新创建对象时将从该文件检索数据。 最后,将修改代码以使用 SOAP 格式保持对象。

安全说明安全说明

本示例创建新的文件(如果该文件尚未存在)。 如果应用程序必须创建文件,则该应用程序必须具有该文件夹的 Create 权限。 权限可使用访问控制列表进行设置。 如果该文件已经存在,则应用程序仅需要 Write 权限(它比 Create 权限弱)。 应尽可能在部署过程中创建文件并仅向单个文件授予 Read 权限(而不是向文件夹授予 Create 权限),这样做更安全。 而且,更为安全的方法是将数据写入用户文件夹,而不是写入根文件夹或“Program Files”文件夹。

安全说明安全说明

本示例将数据存储到二进制或 SOAP 格式的文件中。 不应将这些格式用于敏感数据,如密码或信用卡信息。

提示

显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您现用的设置或版本。 若要更改设置,请单击“工具”菜单上的“导入和导出设置”。 有关更多信息,请参见 Visual Studio 设置

创建 Loan 对象

第一步是创建 Loan 类和使用该类的测试应用程序。

创建 Loan 类

  1. 新建“类库”项目,并将其命名为“LoanClass”。 有关更多信息,请参见如何:创建解决方案和项目

  2. 在**“解决方案资源管理器”中右击 Class1 文件,并单击“重命名”**。 将该文件重命名为 Loan,并按 Enter。 重命名该文件后,会相应地将类重命名为 Loan。

  3. 将以下公共成员添加到该类中:

    Public Class Loan
        Implements System.ComponentModel.INotifyPropertyChanged
    
        Public Property LoanAmount As Double
        Public Property InterestRate As Double
        Public Property Term As Integer
    
        Private p_Customer As String
        Public Property Customer As String
            Get
                Return p_Customer
            End Get
            Set(ByVal value As String)
                p_Customer = value
                RaiseEvent PropertyChanged(Me,
                  New System.ComponentModel.PropertyChangedEventArgs("Customer"))
            End Set
        End Property
    
        Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler _
          Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
        Public Sub New(ByVal loanAmount As Double,
                       ByVal interestRate As Double,
                       ByVal term As Integer,
                       ByVal customer As String)
    
            Me.LoanAmount = loanAmount
            Me.InterestRate = interestRate
            Me.Term = term
            p_Customer = customer
        End Sub
    End Class
    
    public class Loan : System.ComponentModel.INotifyPropertyChanged
    {
        public double LoanAmount {get; set;}
        public double InterestRate {get; set;}
        public int Term {get; set;}
    
        private string p_Customer;
        public string Customer
        {
            get { return p_Customer; }
            set 
            {
                p_Customer = value;
                PropertyChanged(this,
                  new System.ComponentModel.PropertyChangedEventArgs("Customer"));
            }
        }
    
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    
        public Loan(double loanAmount,
                    double interestRate,
                    int term,
                    string customer)
        {
            this.LoanAmount = loanAmount;
            this.InterestRate = interestRate;
            this.Term = term;
            p_Customer = customer;
        }
    }
    

您还必须创建一个使用 Loan 类的简单应用程序。

创建测试应用程序

  1. 若要向解决方案中添加 Windows 窗体应用程序项目,请在**“文件”菜单上指向“添加”,然后单击“新建项目”**。

  2. 在**“添加新项目”对话框中,输入 LoanApp 作为项目的名称,然后单击“确定”**以关闭该对话框。

  3. 在**“解决方案资源管理器”**中选择 LoanApp 项目。

  4. 在**“项目”菜单上,单击“设为启动项目”**。

  5. 在**“项目”菜单上,单击“添加引用”**。

  6. 在**“添加引用”对话框中,选择“项目”**选项卡,然后选择“LoanClass”项目。

  7. 单击**“确定”**关闭对话框。

  8. 在设计器中,将四个 TextBox 控件添加到窗体。

  9. 在代码编辑器中,添加以下代码:

    Private WithEvents TestLoan As New LoanClass.Loan(10000.0, 0.075, 36, "Neil Black")
    
    Private Sub Form1_Load() Handles MyBase.Load
        TextBox1.Text = TestLoan.LoanAmount.ToString
        TextBox2.Text = TestLoan.InterestRate.ToString
        TextBox3.Text = TestLoan.Term.ToString
        TextBox4.Text = TestLoan.Customer
    End Sub
    
    private LoanClass.Loan TestLoan = new LoanClass.Loan(10000.0, 0.075, 36, "Neil Black");
    
    private void Form1_Load(object sender, EventArgs e)
    {
        textBox1.Text = TestLoan.LoanAmount.ToString();
        textBox2.Text = TestLoan.InterestRate.ToString();
        textBox3.Text = TestLoan.Term.ToString();
        textBox4.Text = TestLoan.Customer;
    }
    
  10. 使用以下代码将 PropertyChanged 事件的事件处理程序添加到窗体:

    Public Sub CustomerPropertyChanged(
          ByVal sender As Object,
          ByVal e As System.ComponentModel.PropertyChangedEventArgs
        ) Handles TestLoan.PropertyChanged
    
        MsgBox(e.PropertyName & " has been changed.")
    End Sub
    
    private void CustomerPropertyChanged(object sender, 
        System.ComponentModel.PropertyChangedEventArgs e)
    {
        MessageBox.Show(e.PropertyName + " has been changed.");
    }
    

此时,您就可以生成并运行应用程序了。 请注意,Loan 类的默认值会显示在文本框中。 尝试将利率值从 7.5 更改为 7.1,然后关闭应用程序并再次运行它,利率值会恢复为默认值 7.5。

在现实生活中,利率会定期改变,但不一定是每次运行该应用程序时都改变。 最好在应用程序实例间保持最新的利率,而不是让用户在每次运行应用程序时都更新利率。 在下一步中,将通过向 Loan 类添加序列化来实现这一点。

使用序列化保持对象

为了保持 Loan 类的值,必须先使用 Serializable 特性标记该类。

将类标记为可序列化

  • 更改 Loan 类的类声明,如下所示:

    <Serializable()>
    Public Class Loan
    
    [Serializable()]
    public class Loan : System.ComponentModel.INotifyPropertyChanged
    {
    

Serializable 特性通知编译器可将类中的所有内容保存到文件中。 由于 PropertyChanged 事件由 Windows 窗体对象处理,因此无法对其序列化。 NonSerialized 特性可用于标记不应保留的类成员。

阻止对成员进行序列化

  • 更改 PropertyChanged 事件的声明,如下所示:

    <NonSerialized()>
    Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler _
      Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
    [field: NonSerialized()]
    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    

下一步是向 LoanApp 应用程序添加序列化代码。 为了对类进行序列化并将类写入文件,将使用 System.IOSystem.Xml.Serialization 命名空间。 若要避免键入完全限定名称,您可以添加对必要的类库的引用。

添加对命名空间的引用

  • 将以下语句添加到 Form1 类的顶部:

    Imports System.IO
    Imports System.Runtime.Serialization.Formatters.Binary
    
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    

    在这种情况下,您将使用二进制格式化程序以二进制格式保存对象。 在本演练的后半部分,您将修改代码,以 SOAP 格式保存对象。

下一步是添加执行以下任务的代码:在创建对象时从文件反序列化对象。

反序列化对象

  1. 将常数添加到序列化数据的文件名的类。

    Const FileName As String = "..\..\SavedLoan.bin"
    
    const string FileName = @"..\..\SavedLoan.bin";
    
  2. 修改 Form1_Load 事件过程中的代码,如下所示:

    Private WithEvents TestLoan As New LoanClass.Loan(10000.0, 0.075, 36, "Neil Black")
    
    Private Sub Form1_Load() Handles MyBase.Load
        If File.Exists(FileName) Then
            Dim TestFileStream As Stream = File.OpenRead(FileName)
            Dim deserializer As New BinaryFormatter
            TestLoan = CType(deserializer.Deserialize(TestFileStream), LoanClass.Loan)
            TestFileStream.Close()
        End If
    
        AddHandler TestLoan.PropertyChanged, AddressOf Me.CustomerPropertyChanged
    
        TextBox1.Text = TestLoan.LoanAmount.ToString
        TextBox2.Text = TestLoan.InterestRate.ToString
        TextBox3.Text = TestLoan.Term.ToString
        TextBox4.Text = TestLoan.Customer
    End Sub
    
    private LoanClass.Loan TestLoan = new LoanClass.Loan(10000.0, 0.075, 36, "Neil Black");
    
    private void Form1_Load(object sender, EventArgs e)
    {
        if (File.Exists(FileName))
        {
            Stream TestFileStream = File.OpenRead(FileName);
            BinaryFormatter deserializer = new BinaryFormatter();
            TestLoan = (LoanClass.Loan)deserializer.Deserialize(TestFileStream);
            TestFileStream.Close();
        }
    
        TestLoan.PropertyChanged += this.CustomerPropertyChanged;
    
        textBox1.Text = TestLoan.LoanAmount.ToString();
        textBox2.Text = TestLoan.InterestRate.ToString();
        textBox3.Text = TestLoan.Term.ToString();
        textBox4.Text = TestLoan.Customer;
    }
    

    请注意,首先必须检查该文件是否存在。 如果它存在,请创建 Stream 类以读取该二进制文件,并创建 BinaryFormatter 类以转换该文件。 您还需要从流类型转换为 Loan 对象类型。

接下来,必须添加代码,将在文本框中输入的数据保存到 Loan 类,然后必须将该类序列化到文件中。

保存数据并对类进行序列化

  • 将下面的代码添加到 Form1_FormClosing 事件过程中:

    Private Sub Form1_FormClosing() Handles MyBase.FormClosing
        TestLoan.LoanAmount = CDbl(TextBox1.Text)
        TestLoan.InterestRate = CDbl(TextBox2.Text)
        TestLoan.Term = CInt(TextBox3.Text)
        TestLoan.Customer = TextBox4.Text
    
        Dim TestFileStream As Stream = File.Create(FileName)
        Dim serializer As New BinaryFormatter
        serializer.Serialize(TestFileStream, TestLoan)
        TestFileStream.Close()
    End Sub
    
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        TestLoan.LoanAmount = Convert.ToDouble(textBox1.Text);
        TestLoan.InterestRate = Convert.ToDouble(textBox2.Text);
        TestLoan.Term = Convert.ToInt32(textBox3.Text);
        TestLoan.Customer = textBox4.Text;
    
        Stream TestFileStream = File.Create(FileName);
        BinaryFormatter serializer = new BinaryFormatter();
        serializer.Serialize(TestFileStream, TestLoan);
        TestFileStream.Close();
    }
    

此时,您就可以再次生成并运行该应用程序了。 最初,默认值会显示在文本框中。 尝试更改这些值并在第四个文本框中输入名称。 关闭该应用程序,然后重新运行它。 请注意,新值现在将出现在文本框中。

使用 SOAP 格式保持对象

至此,本示例已经演示了如何使用二进制格式将对象保存到文本文件中。 二进制格式对于大多数 Windows 应用程序均适用。 但对于 Web 应用程序或 Web 服务,您可能希望使用 SOAP 格式将对象保存到 XML 文件中,以使对象易于共享。

为了以 SOAP 格式保持对象,您必须先引用 SoapFormatter 类。 SoapFormatter 类驻留在自己的命名空间 System.Runtime.Serialization.Formatters.Soap 中。

使用 SOAP 格式保持对象

  1. 在**“解决方案资源管理器”**中选择 LoanApp 项目。

  2. 在**“项目”菜单上,单击“添加引用”**。

  3. 在**“添加引用”对话框中,单击“.NET”**选项卡,然后选择 System.Runtime.Serialization.Formatters.Soap 组件。

  4. 单击**“确定”**关闭对话框。

  5. 在**“代码编辑器”**中,将以下语句添加到 Form1 模块的顶部:

    Imports System.Runtime.Serialization.Formatters.Soap
    
    using System.Runtime.Serialization.Formatters.Soap;
    
  6. 将文件名从 SavedLoan.bin 更改为 SavedLoan.xml。

  7. 在 Form1_Load 事件过程中,将 deserializer 变量的声明更改为以下形式:

    Dim deserializer As New SoapFormatter
    
    SoapFormatter deserializer = new SoapFormatter();
    
  8. 在 Form1_FormClosing 事件过程中,将 serializer 变量的声明更改为以下形式:

    Dim serializer As New SoapFormatter
    
    SoapFormatter serializer = new SoapFormatter();
    

此时,您可以生成并测试该应用程序。 第一次运行该应用程序时,会创建 SavedLoan.xml 文件。 若要查看该文件,请在**“解决方案资源管理器”中选择“显示所有文件”**选项;它位于 Windows 应用程序项目的 Bin 节点中。

提示

如果已经处于“显示所有文件”模式下,则必须单击“视图”菜单中的“刷新”来刷新视图以查看此文件。

请注意,LoanClass 的三个成员会以 XML 格式显示。 更改 XML 文件中的 InterestRate 值,然后保存它,并再次运行该应用程序。 新利率将显示在第二个文本框中。

请参见

概念

C# 编程指南

其他资源

序列化(C# 和 Visual Basic)

Visual Basic 编程指南