为了传输/克隆等目的,我需要序列化任何对象(到xml,json,其他 - 不要太在意)。
我发现newtonsoft.json库非常简单,除非它没有序列化私有成员。我在c#中找到了似乎提供我需要使用合同的例子,但我无法让它们起作用。
我将很感激一个简单的例子:
e.g。
Class Person
Private _NI as integer
Public Name as string
End Class
我需要两个功能:
Function SerializePerson(P as person) as string
Function DeSerializePerson(SerializedText as string) as Person
理想情况下,我想要一种易于复制任何对象的方法。
答案 0 :(得分:4)
Newtonsoft的诀窍是更改JsonSerializerSettings
并将其传递给JsonConvert.SerializeObject
。此答案包含此更改的完整详细信息:https://stackoverflow.com/a/24107081/2019162
修改强>
我没想到链接代码在C#中,因为我经常使用它们。我很抱歉。我已经翻译了以下代码:
Dim settings As New JsonSerializerSettings() With {.ContractResolver = New MyContractResolver()}
Dim json As String = JsonConvert.SerializeObject(obj, settings)
合同解决方案:
Imports System.Reflection
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Serialization
Public Class MyContractResolver
Inherits DefaultContractResolver
Protected Overrides Function CreateProperties(type As Type, memberSerialization As MemberSerialization) As IList(Of JsonProperty)
Dim props = type.GetProperties(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).
Select(Function(p) MyBase.CreateProperty(p, memberSerialization)).
Union(type.GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).
Select(Function(f) MyBase.CreateProperty(f, memberSerialization))).ToList()
props.ForEach(Sub(p)
p.Writable = True
p.Readable = True
End Sub)
Return props
End Function
End Class
大多数代码转换器在VB.NET中将C#Lambda更改为Function()
,但如果它们不需要返回类型,则应将它们转换为Sub()
。这可能是导致您出现问题的原因。
答案 1 :(得分:2)
使用DataContractSerializer,您可以使用适当的属性标记要序列化的内容。您尝试使用它时没有分享您尝试过的内容或失败的方式,但具体如下:
Imports System.Runtime.Serialization
Imports System.ComponentModel
<DataContract>
Public Class Employee
<DataMember(Name:="Name")>
Public Property Name As String
<DataMember(Name:="Dept")>
Public Property Dept As String
<DataMember(Name:="Index")>
Public Property Index As Integer
<DataMember(Name:="secret")>
Private secret As Integer
' most serializers require a simple ctor
Public Sub New()
End Sub
Public Sub SetValue(n As Integer)
secret = n
End Sub
End Class
在课程上使用<DataContract>
,在成员上使用<Datamember>
。然后序列化:
' test data
Dim emp As New Employee With {.Name = "Ziggy", .Dept = "Manager", .Index = 2}
emp.SetValue(4) ' set private member value
Dim ser = New DataContractSerializer(GetType(Employee))
Using fs As New FileStream("C:\Temp\DCTest.xml", FileMode.OpenOrCreate),
xw = XmlWriter.Create(fs)
ser.WriteObject(xw, emp)
End Using
输出:
<?xml version="1.0" encoding="utf-8"?>
<Employee xmlns:i="..." xmlns="...">
<Dept>Manager</Dept>
<Index>2</Index>
<Name>Ziggy</Name>
<secret>4</secret>
</Employee>
对于此类事物的一刀切的功能,我个人倾向于将序列化视为类或应用程序或任务特定(我也赞成通过XML 100到1的二进制序列化) ),但是......
Private Function SerializeToString(Of T)(obj As T) As String
' there might be more efficient ways...
' this is off the top of my head
Dim ser = New DataContractSerializer(GetType(T))
Dim xml As String
Using ms As New MemoryStream()
ser.WriteObject(ms, obj)
ms.Position = 0
Using sr As New StreamReader(ms)
xml = sr.ReadToEnd
End Using
End Using
Return xml
End Function
Public Function DeserializeFromString(Of T)(xmlString As String) As T
Dim ser = New DataContractSerializer(GetType(T))
Dim ret As T
Using sr As New StringReader(xmlString),
ms As New MemoryStream(Encoding.Default.GetBytes(sr.ReadToEnd))
ret = CType(ser.ReadObject(ms), T)
End Using
Return ret
End Function
似乎在往返测试中工作:
Dim emp As New Employee With {.Name = "Ziggy", .Dept = "Manager", .Index = 2}
emp.SetValue(4)
Dim str = SerializeToString(Of Employee)(emp)
Dim emp2 As Employee = DeserializeFromString(Of Employee)(str)
' serialize to disk (not shown)
If SerializeToFile("C:\Temp\DCTest.xml", emp) Then
Dim emp3 As Employee = DeserializeFromFile(Of Employee)("C:\Temp\DCTest.xml")
End If
反序列化版本具有正确的私有秘密值:
答案 2 :(得分:1)
我很久以前就试过了,发现最好的解决方案是使用.NET内置二进制序列化,它在保留内部类变量方面最有效。 XML序列化等策略经常因我编写的复杂类而失败,并且在向类添加新成员时,我经常不得不更新我为实现IXmlSerializable而编写的方法。
上下文是我需要将代码从网站传递到Web服务 - 这是我可以将数据从Web区域通过防火墙传递到内部业务服务器的唯一允许方式。我希望将整个对象数据传递到Web服务中以运行一些业务逻辑并执行持久化到数据库位。
解决方案是将二进制序列化为字节数组 - 这是Web服务的允许输入类型 - 以及Web服务中的二进制反序列化。
如果序列化的示例,给定一个返回布鲁尔结果的Web服务并假设您要序列化的对象称为myObject
dim result as boolean
Dim myStream As New System.IO.MemoryStream()
Dim myFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
myFormatter.Serialize(myStream, myObject) '1. Serialise into stream
Dim bytes As Byte() = New Byte(myStream.Length) {}
myStream.Position = 0
myStream.Read(bytes, 0, myStream.Length) '2. read stream into byte array
result = myWebService.PersistObject(bytes)
并且这里是另一端的反序列化位,假设对象的类被称为小部件,并且数据作为名为objectBytes的变量传递给方法
Dim myWidget As New Widget
Dim myStream As New System.IO.MemoryStream()
Dim myFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
myStream.Write(objectBytes, 0, objectBytes.Length)
myStream.Position = 0
myWidget = myFormatter.Deserialize(myStream)
请注意,为此,您必须在接收端包含定义类的类库。但很酷的是它适用于任何类