VB.Net Создать класс для сериализации - PullRequest
0 голосов
/ 09 ноября 2018

Я делаю свой первый урок, а затем сериализую его. Я никогда не работал с сериализацией, и у меня есть некоторые проблемы. Вот код класса:

<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

Вот фрагмент кода, который я использую для тестирования:

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()

И это мой выходной 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>

Во-первых, я хотел бы добавить p: только перед FatturaElettronica, корнем.

Во-вторых, свойство FormatoTrasmissione является Enum, но в моем коде ничего не установлено. Итак, почему сериализация принимает значение FPA12 без присвоения этого значения?

И последнее, но не менее важное ... Я не хотел бы сериализовать свойства, которые не были заполнены. Свойство ContattiTrasmittente пустое, но сериализованное. Почему?

1 Ответ

0 голосов
/ 11 ноября 2018

У вас есть три отдельных вопроса здесь. Давайте тогда сломаться.

Сначала , я хотел бы добавить p: только перед FatturaElettronica, корнем. Это происходит потому, что пространство имен указано через XmlRootAttribute.Namespace* Атрибут 1011 * применяется ко всем дочерним элементам рекурсивно , если не переопределено иное .

Так как вы не хотите этого, самый простой способ предотвратить это - применить <XmlType([Namespace]:="")> к FatturaElettronica. Это применяет пустое пространство имен ко всем дочерним элементам FatturaElettronica, заменяя XmlRootAttribute.Namespace, которое теперь будет применяться только к самому корневому элементу.

Второе , свойство FormatoTrasmissione имеет значение Enum, но в моем коде ничего не установлено. Итак, почему сериализация принимает значение FPA12 без присвоения этого значения?

По умолчанию XmlSerializer сериализует все ненулевые общедоступные свойства и поля. Поскольку enum является типом значения, он по определению ненулевой, и поэтому перечисляемые свойства всегда сериализуются.

Так как вы не хотите этого, вы можете использовать условный шаблон сериализации {propertyName}Specified, который задокументирован в Поддержка привязки схемы XML: поддержка связывания атрибутов MinOccurs и добавить логическое свойство FormatoTrasmissioneSpecified, которое отслеживает было ли когда-либо явно установлено свойство FormatoTrasmissione. В противном случае сериализатор не будет сериализовать свойство.

Третий , я бы не хотел сериализовать свойства, которые не заполнены. Свойство ContattiTrasmittente пустое, но сериализованное. Почему? Это происходит по той же причине, по которой сериализуется свойство FormatoTrasmissione: XmlSerializer будет сериализовать все ненулевые публичные свойства, и вы явно присвоили значение для ContattiTrasmittente в конструкторе DatiTrasmissione:

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

Поскольку вы этого не хотите, вы можете использовать шаблон условной сериализации ShouldSerialize{PropertyName}(), который задокументирован в Свойства в элементах управления Windows Forms: определение значений по умолчанию с использованием методов ShouldSerialize и Reset , и добавить Логический метод ShouldSerializeContattiTrasmittente(), который возвращает false, если ContattiTrasmittente равно нулю или все его свойства равны нулю. Поскольку у вас есть несколько свойств, которые вы выделяете без установки дочерних значений, вам может потребоваться добавить несколько таких методов. В качестве альтернативы вы можете переосмыслить свой дизайн и выделять вложенные свойства только тогда, когда это действительно необходимо.

Подробнее о двух шаблонах условной сериализации см. ShouldSerialize * () vs * Указанный шаблон условной сериализации .

Собрав все это вместе, ваш код должен выглядеть примерно так:

<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

Рабочая скрипка vb.net здесь .

...