VB.Net My.Settings 已保存 SQL 服务器列表的自定义类型

VB.Net My.Settings custom type for list of saved SQL servers

我正在尝试使用 My.Settings 来保存经过身份验证的服务器及其信息的列表,但我无法弄清楚如何制作我的自定义类型。

我现在有一个名为 SqlServer 的 class,它具有以下三个字段:

 Public ServerName As String
 Public UserName As String
 Public Password As String

每次我使用 SQL 身份验证连接到 SQL 服务器时,我想保存该服务器和登录信息。这意味着我需要一个自定义类型,它是 My.Settings 中 SqlServer 的集合。

这是我目前的代码:

Public Class SQLServerList
  Inherits List(Of SQLServer)
  Implements IComparable(Of SQLServer)

  Public Function CompareTo(ByVal SqlServerInfo As SQLServer) As Integer Implements IComparable(Of MyProjectName.SQLServer).CompareTo
    ...
  End Function
End Class

我继承 List 的方向是否正确?我需要什么样的 properties/fields 才能让这个东西按我想要的方式运行?谢谢。

如果你想保存一些你定义的 class 到 My.Settings 你基本上需要满足与任何 XML-serializable class.

  • 您的 class 必须是可序列化的。
  • 您的 class 必须有一个 public 不带参数的默认构造函数。
  • 您 class 中任何来自 .NET 的类型的 属性 都必须是可序列化的。
  • 您的 class 中包含的任何 class 都必须满足这些相同的要求。

给定一个集合 class,很容易让它自己序列化内容。

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

<Serializable>
Public Class Server
    Public Property Name As String
    Public Property UserName As String
    Public Property Password As String
End Class

一个简单的合集class:

<Serializable>
Public Class Servers
    Private myList As List(Of Server)

    Public Sub New()
        myList = New List(Of Server)
    End Sub

    Public Sub Add(svr As Server)
        myList.Add(svr)
    End Sub

    ' no reason it cant also create server objects for you
    Public Sub Add(sname As String, uname As String, pw As String)
        myList.Add(New Server With {.Name = sname, .UserName = uname, .Password = pw})
    End Sub

    'toDo Contains, Count, Item etc as needed

    Public Sub Save(mypath As String)
        Using fs As New FileStream(mypath, FileMode.OpenOrCreate)
            Dim bf As New BinaryFormatter
            bf.Serialize(fs, myList)
        End Using
    End Sub

    Public Function Load(mypath As String) As Int32
        'ToDo: check if file exists
        Using fs As New FileStream(mypath, FileMode.Open)
            Dim bf As New BinaryFormatter
            myList = CType(bf.Deserialize(fs), List(Of Server))
        End Using

        If myList IsNot Nothing Then
            Return myList.Count
        Else
            Return 0
        End If
    End Function
End Class

BinaryFormatter 需要 <Serializable> 属性。不同的序列化器(json、ProtoBuf-NET)可能有自己的序列化器。

"magic" 在 SaveLoad 方法中,它们序列化或反序列化对象的内部列表。只需几行代码即可 load/save 1 或 1000 个项目。对于少量数据,它是数据库的绝佳替代品。

正在测试往返:

    Dim svrs As New Servers
    svrs.Add("SqlSS1", "ziggy", "foo")
    svrs.Add("SqlSS2", "zacky", "bar")
    svrs.Add("SqlSS3", "zoey", "baz")

    svrs.Save("C:\Temp\SSvrs.bin")

    ' now load to a new Servers collection
    ' to test the round trip
    Dim svrs2 As New Servers
    Dim sCount = svrs2.Load("C:\Temp\SSvrs.bin")

    For n = 0 To sCount  - 1
        Console.WriteLine("{0}  {1}   {2} ", svrs2(n).Name, svrs2(n).UserName, svrs2(n).Password)
    Next

输出:

SqlSS1 ziggy foo
SqlSS2 zacky bar
SqlSS3 zoey baz

我使用了 BinaryFormatter(没有真正原因),但 ProtoBuf-NET 或 XMLSerializer 也可以。由于数据都是字符串,您可能希望对它们进行加密(将文件流包装在密码流中)。

基准测试,将对象序列化为二进制文件、XML文件和XML字符串:

  • 将 500.000 个对象写入二进制文件(1954 毫秒/23MB)
  • 将 500.000 个对象写入 XML 文件(660 毫秒/46MB)
  • 将 500.000 个对象写入 XML-字符串(847 毫秒,进程 38MB->348MB)

惊讶地发现写入二进制文件比 XML 文件花费的时间更长。我希望 .Net 只是将内存转储到文件而不进行任何处理和转换。也许有比使用的更好的二进制序列化程序?

虽然预计会更小。 XML 文件 "only" 的开销为 100%。

看到写入 XML 文件比写入内存中的字符串更快也令人惊讶。

我确定我的代码可以优化,因为它很奇怪,请随意贡献:-)

要序列化的对象:

<Serializable> _
Public Class oNames
    Public Shared cNames As New List(Of oName)

    <Serializable> _
    Public Class oName
        Public Property Firstname As String
        Public Property Lastname As String
        Sub New()
        End Sub
    End Class

    Sub New()
    End Sub
End Class

500.000 个对象填充列表:

 oNames.cNames.Clear()
 For i As Integer = 1 To 500000
     oNames.cNames.Add(New oNames.oName With {.Firstname = "MyFirstName" & i.ToString, .Lastname = "MyLastName" & i.ToString})
 Next

写入二进制文件(使用我自己的序列化器class):

 WCC.BinSerialization.ToFile(oNames.cNames, "c:\temp\ObjToBin.bin", IO.FileMode.Append)

写入XML文件(使用我自己的序列化器class):

 WCC.XMLSerialization.Obj_To_XMLFile(oNames.cNames, "c:\temp\ObjToXML.xml")

写入XML-string(使用我自己的序列化器class):

 Dim XMLStr As String
 XMLStr = WCC.XMLSerialization.Obj_To_XLMStr(oNames.cNames)

我的序列化器class:

 Public Class WCC
     Public Class XMLSerialization

       Public Shared Function Obj_To_XLMStr(Obj As Object) As String
          Using SW As New System.IO.StringWriter
              Dim X As New System.Xml.Serialization.XmlSerializer(Obj.GetType)
              X.Serialize(SW, Obj)
              Return SW.ToString
           End Using
       End Function

       Public Shared Sub XMLStr_To_Obj(XMLString As String, ByRef ListObj As Object)
           Using SR As New System.IO.StringReader(XMLString)
              Dim X As New System.Xml.Serialization.XmlSerializer(ListObj.GetType)
              ListObj = X.Deserialize(SR)
           End Using
       End Sub

       Public Shared Sub Obj_To_XMLFile(Obj As Object, Path As String)
           Dim XWS As New System.Xml.XmlWriterSettings
           XWS.Indent = True
           XWS.IndentChars = vbTab
           Using XW As System.Xml.XmlWriter = System.Xml.XmlWriter.Create(Path, XWS)
              Dim X As New System.Xml.Serialization.XmlSerializer(Obj.GetType)
              X.Serialize(XW, Obj)
           End Using
       End Sub
     End Class

     Public Class BinSerialization
       Public Shared Sub ToFile(Obj As Object, Path As String, FileMode As IO.FileMode)
           Using fs As New System.IO.FileStream(Path, FileMode)
              Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
              bf.Serialize(fs, Obj)
           End Using
       End Sub
     End Class
 End Class