Domanda

Ho avuto qualche problema con la serializzazione dei miei oggetti e ho ridotto il problema a un caso specifico (vedi il codice sotto). Stavo ottenendo il seguente errore:

Errore 1 File Resx non valido. Impossibile caricare il tipo Serialisation.Harness.Blob, Serialization, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null utilizzato nel file .RESX. Assicurati che i riferimenti necessari siano stati aggiunti al tuo progetto. Linea 129, posizione 5. ...

Ora la cosa davvero strana è che il riavvio di Visual Studio provoca la scomparsa dell'errore e il funzionamento del codice, ma dopo un numero apparentemente casuale di build (durante le quali il suddetto codice è non modificato) si romperà di nuovo.

Riesci a vedere cosa sto facendo di sbagliato / perdendo?

Molte grazie in anticipo,

Meto

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design; using System.ComponentModel.Design;

namespace Serialisation.Harness
{    

    [Serializable]
    public class Blob
    {
        public Blob()
        {
        }
    }

    [Serializable]
    public class Basic
    {

        private List<Blob> blobs;
        public List<Blob> Blobs
        {
            get { return blobs; }
            set { this.blobs= value; }
        }

        public Basic()
        {
            basics = new List<Blob>();
        }

    }

    public class BasicComponent : Component
    {

        private Basic basic = new Basic();

        private IContainer components = new Container();

        public List<Blob> Blobs
        {
            get { return basic.Blobs; }
            set { basic.Blobs= value; }
        }

        public BasicComponent(IContainer container)
        {
            container.Add(this);
        }

    }

}
È stato utile?

Soluzione

Innanzitutto l'attributo Serializable è non utilizzato per la serializzazione del designer. Durante la serializzazione degli oggetti, il progettista serializzerà nel file di risorse quando non sa come scriverlo nel codice del progettista. Questo lo scrive nel resx come un BLOB usando un InstanceDescriptor per il costruttore predefinito del tipo di oggetto (questo perde qualsiasi valore di proprietà che potresti voler includere). Questo è ciò che sta accadendo per la proprietà Blobs in quanto il progettista non serializza bene elenchi generici (ma sa come serializzare le matrici).

Al fine di conservare le informazioni all'interno di questi oggetti persistenti, sarà necessario creare un TypeConverter che specifica un costruttore diverso nel BasicComponent (uno che in realtà richiede uno stato per descrivere le proprietà, come la proprietà IEnumerable<Blob>). Ad esempio, se hai aggiunto un costruttore al tuo Blob tipo che accetta un List<Blob>, potresti ottenere un CodeDomSerializer a quel costruttore, passando un array di <=> s (creeresti un nuovo <=> attorno a quello nel costruttore ). Perché il designer sa come persistere un <=> al codice e poiché sa come persistere le matrici al codice, aggiungerebbe questo al codice del designer anziché al resx.

Puoi anche implementare un <=> per specificare il codice utilizzato per descrivere l'istanza, che il designer può utilizzare per salvare l'oggetto nel codice del designer anziché nel resx.

Convertitore di tipi

Per usare l'approccio del convertitore di tipi, potresti fare qualcosa del genere:

public class BasicComponentTypeConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        bool canConvert = base.CanConvertTo(context, destinationType);

        if (!canConvert &&
            (destinationType == typeof(InstanceDescriptor))
        {
            canConvert = true;
        }

        return canConvert;
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        object conversion = null;

        if (culture == null)
        {
            culture = CultureInfo.CurrentCulture;
        }

        BasicComponent component = value as BasicComponent;
        if (basicComponent != null)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
               // Note that we convert the blobs to an array as this makes for nicer persisted code output.
               // Without it, we might just get a resource blob which is not human-readable.
               conversion = new InstanceDescriptor(
                   typeof(BasicComponent).GetConstructor(new Type[] { typeof(IEnumerable<Blob>) }),
                   new object[] { basicComponent.Blobs.ToArray() },
                   true);
            }
        }

        if (conversion == null)
        {
            conversion = base.ConvertTo(context, culture, value, destinationType);
        }

        return conversion;
    }
}

Nota che potrebbe essere necessario scrivere un convertitore di tipi anche per il tipo <=>. Per collegare il convertitore di tipi al tipo, dichiarare <=> attributo sulla classe che convertirà il convertitore di tipi, ovvero BasicConverter per l'esempio sopra.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top