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

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

备注

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

在本演练中,将创建一个简单的 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 编程指南