简体   繁体   中英

VB.Net Create a class to serialize

I'm making my first class and then serializing it. I've never worked with serialization and I'm having some problems. Here is the class code:

<XmlRoot([Namespace]:="FatturaElettronica")>
Public Class FatturaElettronica
    Public quantity As Integer

    Sub New()
        FatturaElettronicaHeader = New FatturaElettronicaHeader
    End Sub

    Property FatturaElettronicaHeader As FatturaElettronicaHeader
End Class

Public Class FatturaElettronicaHeader
    Sub New()
        DatiTrasmissione = New DatiTrasmissione
    End Sub

    Property DatiTrasmissione As DatiTrasmissione
End Class

Public Class DatiTrasmissione
    Sub New()
        Idtrasmittente = New idTrasmittente
        ContattiTrasmittente = New ContattiTrasmittente
    End Sub

    Property Idtrasmittente As idTrasmittente
    Property ProgressivoInvio As String
    Property FormatoTrasmissione As FormatoTrasmissioneType
    Property CodiceDestinatario As String
    Property ContattiTrasmittente As ContattiTrasmittente
    Property PecDestinatario As String
End Class

Public Class idTrasmittente
    Property IdPaese As String
    Property IdCodice As String
End Class

Public Class ContattiTrasmittente
    Property Telefono As String
    Property Email As String
End Class

Public Enum FormatoTrasmissioneType
    FPA12
    FPR12
End Enum

Here is a bit of code that I use for testing:

Dim fattEle As New FatturaElettronica
Dim ns2 As New Xml.Serialization.XmlSerializerNamespaces()

ns2.Add("p", "FatturaElettronica")
Dim ser As Xml.Serialization.XmlSerializer = New Xml.Serialization.XmlSerializer(fattEle.GetType)
Dim stream As New IO.FileStream("c:/lavoro/example2.xml", IO.FileMode.Create)
ser.Serialize(stream, fattEle, ns2)
stream.Close()

And this is my output XML:

<?xml version="1.0"?>
<p:FatturaElettronica xmlns:p="FatturaElettronica">
    <p:FatturaElettronicaHeader>
        <p:DatiTrasmissione>
            <p:Idtrasmittente />
            <p:FormatoTrasmissione>FPA12</p:FormatoTrasmissione>
            <p:ContattiTrasmittente />
        </p:DatiTrasmissione>
    </p:FatturaElettronicaHeader>
</p:FatturaElettronica>

First, I would like to add the p: only before FatturaElettronica , the root.

Second, the FormatoTrasmissione property is an Enum , but in my code isn't being set to anything. So, why is the serialization assuming the value FPA12 without that value being assigned?

Last but, not least... I would like to not serialize the properties that are not filled. The ContattiTrasmittente property is empty, but serialized. Why?

You have three separate questions here. Let's break then down.

First , I would like to add p: only before FatturaElettronica , the root. This is happening because the namespace specified via the XmlRootAttribute.Namespace attribute applies to all child elements recursively unless otherwise overridden .

Since you don't want this, the easiest way to prevent it is to apply <XmlType([Namespace]:="")> to FatturaElettronica as well. This applies the empty namespace to all child elements of FatturaElettronica , superseding XmlRootAttribute.Namespace which will now only apply to the root element itself.

Second , the FormatoTrasmissione property is an Enum , but in my code isn't being set to anything. So, why is the serialization assuming the value FPA12 without that value being assigned?

By default, XmlSerializer serializes all non-null public properties and fields. Since an enum is a value type, it is non-null by definition, and thus enum-valued properties are always serialized.

Since you don't want this, you can use the {propertyName}Specified conditional serialization pattern that is documented in XML Schema Binding Support: MinOccurs Attribute Binding Support and add a FormatoTrasmissioneSpecified Boolean property that tracks whether the FormatoTrasmissione property was ever explicitly set. If not, the serializer will not serialize the property.

Third , I would like to not serialize the properties that are not filled. The ContattiTrasmittente property is empty, but serialized. Why? This is happening for the same reason that the FormatoTrasmissione property is serialized: XmlSerializer will serialize all non-null public properties, and you explicitly allocated a value for ContattiTrasmittente in the DatiTrasmissione constructor:

Public Class DatiTrasmissione
    Sub New()
        Idtrasmittente = New idTrasmittente
        ContattiTrasmittente = New ContattiTrasmittente
    End Sub

Since you don't want this, you can use the ShouldSerialize{PropertyName}() conditional serialization pattern which is documented in Properties in Windows Forms Controls: Defining Default Values with the ShouldSerialize and Reset Methods , and add a Boolean method ShouldSerializeContattiTrasmittente() that returns false when ContattiTrasmittente is null, or all its properties are null. As you have multiple properties you are allocating without setting any child values, you may need to add multiple such methods. Alternatively, you might re-think your design and only allocate nested properties when actually needed.

For more details on the two conditional serialization patterns see ShouldSerialize*() vs *Specified Conditional Serialization Pattern .

Putting all this together, you code should looks something like:

<XmlRoot([Namespace]:="FatturaElettronica")>
<XmlType([Namespace]:="")> ' Fixed added empty namespace for all elements.
Public Class FatturaElettronica
    Public quantity As Integer

    Sub New()
        FatturaElettronicaHeader = New FatturaElettronicaHeader
    End Sub

    Property FatturaElettronicaHeader As FatturaElettronicaHeader
End Class

Public Class FatturaElettronicaHeader
    Sub New()
        DatiTrasmissione = New DatiTrasmissione
    End Sub

    Property DatiTrasmissione As DatiTrasmissione
End Class

Public Class DatiTrasmissione
    Sub New()
        Idtrasmittente = New idTrasmittente
        ' By allocating ContattiTrasmittente you cause its value to be serialized by default
        ContattiTrasmittente = New ContattiTrasmittente
    End Sub

    Property Idtrasmittente As idTrasmittente
    Property ProgressivoInvio As String

    ' Fixed added FormatoTrasmissioneSpecified and made FormatoTrasmissione an explicitly implemented property
    Private m_FormatoTrasmissione as FormatoTrasmissioneType

    <XmlIgnore>
    Public Property FormatoTrasmissioneSpecified as Boolean

    Property FormatoTrasmissione As FormatoTrasmissioneType
        Get
            Return m_FormatoTrasmissione
        End Get
        Set
            ' For convenience set FormatoTrasmissioneSpecified automatically when the property is set publicly.
            FormatoTrasmissioneSpecified = true
            m_FormatoTrasmissione = value
        End Set
    End Property

    Property CodiceDestinatario As String

    ' Fixed added ShouldSerializeContattiTrasmittente()
    Property ContattiTrasmittente As ContattiTrasmittente

    Public Function ShouldSerializeContattiTrasmittente() as Boolean
        Return ContattiTrasmittente.ShouldSerialize()
    End Function

    Property PecDestinatario As String
End Class

Public Class idTrasmittente
    Property IdPaese As String
    Property IdCodice As String
End Class

Public Class ContattiTrasmittente
    Property Telefono As String
    Property Email As String
End Class

' Fixed added an extension method to test whether a ContattiTrasmittente should be serialized.
Public Module ContattiTrasmittenteExtensions  
    <System.Runtime.CompilerServices.Extension()> _
    Public Function ShouldSerialize(ByVal ContattiTrasmittente as ContattiTrasmittente) as Boolean
        Return ContattiTrasmittente IsNot Nothing And (ContattiTrasmittente.Telefono IsNot Nothing Or ContattiTrasmittente.Email IsNot Nothing)
    End Function
End Module

Public Enum FormatoTrasmissioneType
    FPA12
    FPR12
End Enum

Working vb.net fiddle here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM