Serializzazione personalizzataCustom serialization

La serializzazione personalizzata è il processo di controllo della serializzazione e deserializzazione di un tipo.Custom serialization is the process of controlling the serialization and deserialization of a type. Tramite il controllo della serializzazione è possibile garantire la compatibilità della serializzazione stessa, ovvero la possibilità di eseguire la serializzazione e la deserializzazione tra versioni di un tipo senza compromettere la funzionalità principale del tipo stesso.By controlling serialization, it's possible to ensure serialization compatibility, which is the ability to serialize and deserialize between versions of a type without breaking the core functionality of the type. Ad esempio, nella prima versione di un tipo potrebbero essere presenti solo due campi.For example, in the first version of a type, there may be only two fields. Nella versione successiva di un tipo, vengono aggiunti molti altri campi.In the next version of a type, several more fields are added. La seconda versione di un'applicazione deve comunque essere in grado di serializzare e deserializzare entrambi i tipi.Yet the second version of an application must be able to serialize and deserialize both types. Nelle seguenti sezioni viene descritto come controllare la serializzazione:The following sections describe how to control serialization.

Avviso

La serializzazione binaria può rappresentare un pericolo.Binary serialization can be dangerous. Non deserializzare mai dati da un'origine non attendibile e non eseguire il round trip per i dati serializzati verso sistemi non sotto il proprio controllo.Never deserialize data from an untrusted source and never round-trip serialized data to systems not under your control.

Importante

Nelle versioni precedenti a .NET Framework 4.0, la serializzazione di dati utente personalizzati in un assembly parzialmente attendibile era eseguita tramite GetObjectData.In versions previous to .NET Framework 4.0, serialization of custom user data in a partially trusted assembly was accomplished using the GetObjectData. A partire dalla versione 4.0 questo metodo è contrassegnato dall'attributo SecurityCriticalAttribute che impedisce esecuzione negli assembly parzialmente attendibili.Starting with version 4.0, that method is marked with the SecurityCriticalAttribute attribute which prevents execution in partially trusted assemblies. Per ovviare a questa condizione, implementare l'interfaccia ISafeSerializationData.To work around this condition, implement the ISafeSerializationData interface.

Esecuzione di metodi personalizzati durante e dopo la serializzazioneRunning custom methods during and after serialization

La procedura consigliata e il modo più semplice (introdotto nella versione 2.0 di .NET Framework) consiste nell'applicare i seguenti attributi ai metodi utilizzati per correggere i dati durante e dopo la serializzazione:The best practice and easiest way (introduced in version 2.0 of the .NET Framework) is to apply the following attributes to methods that are used to correct data during and after serialization:

Tali attributi consentono al tipo di partecipare a una o a tutte le quattro fasi dei processi di serializzazione e deserializzazione.These attributes allow the type to participate in any one of, or all four of the phases, of the serialization and deserialization processes. Gli attributi specificano i metodi del tipo che devono essere richiamati durante ogni fase.The attributes specify the methods of the type that should be invoked during each phase. I metodi non accedono al flusso di serializzazione ma consentono di modificare l'oggetto prima e dopo la serializzazione o prima e dopo la deserializzazione.The methods do not access the serialization stream but instead allow you to alter the object before and after serialization, or before and after deserialization. Gli attributi possono essere applicati a tutti i livelli della gerarchia di ereditarietà del tipo e ogni metodo viene chiamato nella gerarchia dalla base al più derivato.The attributes can be applied at all levels of the type inheritance hierarchy, and each method is called in the hierarchy from the base to the most derived. Tale meccanismo consente di evitare la complessità e il rischio di problemi risultanti dall'implementazione dell'interfaccia ISerializable, dando la responsabilità della serializzazione e deserializzazione all'implementazione più derivata.This mechanism avoids the complexity and any resulting issues of implementing the ISerializable interface by giving the responsibility for serialization and deserialization to the most derived implementation. Inoltre, tale meccanismo consente ai formattatori di ignorare l'inserimento di campi e il recupero dal flusso di serializzazione.Additionally, this mechanism allows the formatters to ignore the population of fields and retrieval from the serialization stream. Per dettagli ed esempi di serializzazione e deserializzazione di controllo, fare clic su uno dei collegamenti precedenti.For details and examples of controlling serialization and deserialization, click any of the previous links.

Inoltre, quando si aggiunge un nuovo campo a un tipo serializzabile esistente, applicare l'attributo OptionalFieldAttribute al campo.In addition, when adding a new field to an existing serializable type, apply the OptionalFieldAttribute attribute to the field. Le classi BinaryFormatter e SoapFormatter ignorano l'assenza del campo se viene elaborato un flusso a cui risulta mancante il nuovo campo.The BinaryFormatter and the SoapFormatter ignores the absence of the field when a stream that is missing the new field is processed.

Implementazione dell'interfaccia ISerializableImplementing the ISerializable interface

L'altro modo per controllare la serializzazione prevede l'implementazione dell'interfaccia ISerializable per un oggetto.The other way to control serialization is achieved by implementing the ISerializable interface on an object. Notare tuttavia che il metodo descritto nella sezione precedente sostituisce tale metodo per il controllo della serializzazione.Note, however, that the method in the previous section supersedes this method to control serialization.

In aggiunta, la serializzazione predefinita non deve essere usata per una classe contrassegnata con l'attributo Serializable e dotata di sicurezza dichiarativa o imperativa al livello della classe. La serializzazione non deve essere usata neanche per i costruttori di questa classe.In addition, you should not use default serialization on a class that is marked with the Serializable attribute and has declarative or imperative security at the class level or on its constructors. Tali classi devono invece implementare sempre l'interfaccia ISerializable.Instead, these classes should always implement the ISerializable interface.

L'implementazione dell'interfaccia ISerializable prevede l'implementazione del metodo GetObjectData e di un costruttore speciale usato quando l'oggetto viene deserializzato.Implementing ISerializable involves implementing the GetObjectData method and a special constructor that is used when the object is deserialized. Nell'esempio di codice riportato di seguito viene mostrato come implementare l'interfaccia ISerializable sulla classe MyObject da una sezione precedente.The following sample code shows how to implement ISerializable on the MyObject class from a previous section.

[Serializable]
public class MyObject : ISerializable
{
    public int n1;
    public int n2;
    public String str;

    public MyObject()
    {
    }

    protected MyObject(SerializationInfo info, StreamingContext context)
    {
      n1 = info.GetInt32("i");
      n2 = info.GetInt32("j");
      str = info.GetString("k");
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("i", n1);
        info.AddValue("j", n2);
        info.AddValue("k", str);
    }
}
<Serializable()>  _
Public Class MyObject
    Implements ISerializable
    Public n1 As Integer
    Public n2 As Integer
    Public str As String

    Public Sub New()
    End Sub

    Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
        n1 = info.GetInt32("i")
        n2 = info.GetInt32("j")
        str = info.GetString("k")
    End Sub 'New

    <SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter := True)> _
    Public Overridable Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
        info.AddValue("i", n1)
        info.AddValue("j", n2)
        info.AddValue("k", str)
    End Sub
End Class

Se il metodo GetObjectData viene chiamato durante la serializzazione, è compito dell'utente popolare l'oggetto SerializationInfo specificato con la chiamata al metodo.When GetObjectData is called during serialization, you are responsible for populating the SerializationInfo provided with the method call. Aggiungere le variabili da serializzare come coppie di nomi e valori.Add the variables to be serialized as name and value pairs. Come nome è possibile utilizzare qualsiasi testo.Any text can be used as the name. È possibile decidere quali variabili membro vanno aggiunte a SerializationInfo, purché vengano serializzati dati sufficienti per il ripristino dell'oggetto durante la deserializzazione.You have the freedom to decide which member variables are added to the SerializationInfo, provided that sufficient data is serialized to restore the object during deserialization. Le classi derivate devono chiamare il metodo GetObjectData per l'oggetto di base se quest'ultimo implementa ISerializable.Derived classes should call the GetObjectData method on the base object if the latter implements ISerializable.

Notare che la serializzazione può consentire ad altro codice di visualizzare o modificare i dati dell'istanza dell'oggetto altrimenti inaccessibili.Note that serialization can allow other code to see or modify object instance data that is otherwise inaccessible. Il codice che esegue la serializzazione, quindi, richiede SecurityPermission con il flag SerializationFormatter specificato.Therefore, code that performs serialization requires the SecurityPermission with the SerializationFormatter flag specified. In base ai criteri predefiniti, questa autorizzazione non è concessa a codice scaricato da Internet o a codice Intranet, ma solo al codice presente sul computer locale.Under default policy, this permission is not given to Internet-downloaded or intranet code; only code on the local computer is granted this permission. Il metodo GetObjectData deve essere protetto in modo esplicito tramite la richiesta di SecurityPermission con il flag SerializationFormatter specificato o tramite la richiesta di altre autorizzazioni che consentono di proteggere i dati privati in modo specifico.The GetObjectData method must be explicitly protected either by demanding the SecurityPermission with the SerializationFormatter flag specified or by demanding other permissions that specifically help protect private data.

Se un campo privato memorizza informazioni riservate, è necessario proteggere i dati richiedendo le autorizzazioni appropriate per GetObjectData.If a private field stores sensitive information, you should demand the appropriate permissions on GetObjectData to protect the data. Si ricordi che il codice a cui è stato concesso SecurityPermission con il flag SerializationFormatter specificato può visualizzare e modificare i dati memorizzati nei campi privati.Remember that code that has been granted SecurityPermission with the SerializationFormatter flag specified can view and modify the data stored in private fields. Un chiamante dannoso a cui venga concesso l'attributo SecurityPermission può visualizzare dati quali percorsi di directory nascoste o autorizzazioni concesse e può usare tali dati per sfruttare una vulnerabilità di sicurezza nel computer.A malicious caller granted this SecurityPermission can view data such as hidden directory locations or granted permissions and use the data to exploit a security vulnerability on the computer. Per un elenco completo dei flag di autorizzazione di sicurezza che è possibile specificare, vedere l'enumerazione SecurityPermissionFlag.For a complete list of the security permission flags you can specify, see the SecurityPermissionFlag Enumeration.

È importante sottolineare che quando si aggiunge ISerializable a una classe, è necessario implementare sia GetObjectData che il costruttore speciale.It's important to stress that when ISerializable is added to a class you must implement both GetObjectData and the special constructor. Se GetObjectData manca, il compilatore visualizza un avviso.The compiler warns you if GetObjectData is missing. Tuttavia, poiché è impossibile applicare l'implementazione di un costruttore, non viene visualizzato alcun avviso nel caso in cui sia assente il costruttore e viene generata un'eccezione se si tenta di deserializzare una classe senza il costruttore.However, because it is impossible to enforce the implementation of a constructor, no warning is provided if the constructor is absent, and an exception is thrown when an attempt is made to deserialize a class without the constructor.

La progettazione corrente è stata preferita rispetto a un metodo SetObjectData in modo da evitare eventuali problemi di sicurezza e di controllo della versione.The current design was favored above a SetObjectData method to get around potential security and versioning problems. Ad esempio, un metodo SetObjectData deve essere pubblico se è definito come parte di un'interfaccia; in tal modo gli utenti devono scrivere codice per evitare che il metodo SetObjectData venga chiamato più volte.For example, a SetObjectData method must be public if it is defined as part of an interface; thus users must write code to defend against having the SetObjectData method called multiple times. In caso contrario, un'applicazione dannosa che chiami il metodo SetObjectData per un oggetto in fase di esecuzione di un'operazione può provocare problemi potenziali.Otherwise, a malicious application that calls the SetObjectData method on an object in the process of executing an operation can cause potential problems.

Durante la deserializzazione, SerializationInfo viene passato alla classe tramite il costruttore fornito a tale scopo.During deserialization, SerializationInfo is passed to the class using the constructor provided for this purpose. Eventuali vincoli di visibilità posizionati sul costruttore vengono ignorati quando l'oggetto viene deserializzato; in tal modo è possibile contrassegnare la classe come pubblica, protetta, interna, o privata.Any visibility constraints placed on the constructor are ignored when the object is deserialized; so you can mark the class as public, protected, internal, or private. Tuttavia, è una procedura consigliata rendere il costruttore protetto a meno che la classe non sia sigillata; in tal caso il costruttore deve essere contrassegnato come privato.However, it is a best practice to make the constructor protected unless the class is sealed, in which case the constructor should be marked private. Il costruttore deve inoltre eseguire la convalida di input approfondita.The constructor should also perform thorough input validation. Per evitare un uso inappropriato da parte di codice dannoso, il costruttore deve applicare gli stessi controlli e autorizzazioni di sicurezza richiesti per ottenere un'istanza della classe mediante l'utilizzo di un qualunque altro costruttore.To avoid misuse by malicious code, the constructor should enforce the same security checks and permissions required to obtain an instance of the class using any other constructor. Se non si segue questo consiglio, il codice dannoso può preserializzare un oggetto, ottenere il controllo con SecurityPermission con il flag SerializationFormatter specificato e deserializzare l'oggetto in un computer client, evitando qualsiasi misura di sicurezza applicata durante la costruzione standard dell'istanza tramite un costruttore pubblico.If you do not follow this recommendation, malicious code can preserialize an object, obtain control with the SecurityPermission with the SerializationFormatter flag specified and deserialize the object on a client computer bypassing any security that would have been applied during standard instance construction using a public constructor.

Per ripristinare lo stato dell'oggetto, è sufficiente recuperare i valori delle variabili da SerializationInfo utilizzando i nomi utilizzati durante la serializzazione.To restore the state of the object, simply retrieve the values of the variables from SerializationInfo using the names used during serialization. Se la classe di base implementa ISerializable, il costruttore di base deve essere chiamato in modo da consentire all'oggetto di base di ripristinare le variabili.If the base class implements ISerializable, the base constructor should be called to allow the base object to restore its variables.

Se si deriva una nuova classe da una classe che implementa ISerializable e la classe derivata contiene variabili che devono essere serializzate, questa deve implementare sia il costruttore che il metodo GetObjectData.When you derive a new class from one that implements ISerializable, the derived class must implement both the constructor as well as the GetObjectData method if it has variables that need to be serialized. Nell'esempio di codice riportato di seguito viene mostrato come viene eseguita tale operazione tramite l'utilizzo della classe MyObject mostrata in precedenza.The following code example shows how this is done using the MyObject class shown previously.

[Serializable]
public class ObjectTwo : MyObject
{
    public int num;

    public ObjectTwo()
      : base()
    {
    }

    protected ObjectTwo(SerializationInfo si, StreamingContext context)
      : base(si, context)
    {
        num = si.GetInt32("num");
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo si, StreamingContext context)
    {
        base.GetObjectData(si,context);
        si.AddValue("num", num);
    }
}
<Serializable()>  _
Public Class ObjectTwo
    Inherits MyObject
    Public num As Integer

    Public Sub New()

    End Sub

    Protected Sub New(ByVal si As SerializationInfo, _
    ByVal context As StreamingContext)
        MyBase.New(si, context)
        num = si.GetInt32("num")
    End Sub

    <SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter := True)> _
    Public Overrides Sub GetObjectData(ByVal si As SerializationInfo, ByVal context As StreamingContext)
        MyBase.GetObjectData(si, context)
        si.AddValue("num", num)
    End Sub
End Class

Non dimenticare di chiamare la classe di base nel costruttore di deserializzazione.Don't forget to call the base class in the deserialization constructor. Se tale operazione non viene eseguita, il costruttore per la classe di base non viene mai chiamato e l'oggetto non viene costruito completamente dopo la deserializzazione.If this isn't done, the constructor on the base class is never called, and the object is not fully constructed after deserialization.

Gli oggetti vengono ricostruiti dall'interno all'esterno; durante la deserializzazione, i metodi di chiamata possono avere effetti collaterali indesiderati, poiché i metodi chiamati potrebbero fare riferimento a riferimenti a oggetti che non sono stati deserializzati al momento dell'esecuzione della chiamata.Objects are reconstructed from the inside out; and calling methods during deserialization can have undesirable side effects, because the methods called might refer to object references that have not been deserialized by the time the call is made. Se la classe in fase di deserializzazione implementa IDeserializationCallback, il metodo OnDeserialization viene chiamato automaticamente dopo la deserializzazione dell'intero oggetto grafico.If the class being deserialized implements the IDeserializationCallback, the OnDeserialization method is automatically called when the entire object graph has been deserialized. In questa fase, tutti gli oggetti figlio a cui si fa riferimento sono stati ripristinati pienamente.At this point, all the child objects referenced have been fully restored. Una tabella hash è un esempio tipico di una classe difficile da deserializzare senza l'utilizzo del listener di eventi.A hash table is a typical example of a class that is difficult to deserialize without using the event listener. È facile recuperare le coppie chiave/valore durante la deserializzazione, tuttavia aggiungere nuovamente tali oggetti alla tabella hash può provocare problemi, poiché non c'è nessuna garanzia che le classi derivate dalla tabella hash siano state deserializzate.It is easy to retrieve the key and value pairs during deserialization, but adding these objects back to the hash table can cause problems, because there is no guarantee that classes that derived from the hash table have been deserialized. I metodi di chiamata su una tabella hash in questa fase non sono pertanto consigliabili.Calling methods on a hash table at this stage is therefore not advisable.

Vedere ancheSee also