Вопрос

У меня возникла проблема с сериализацией моих объектов, и я сузил проблему до конкретного случая (см. код ниже).Я получал следующую ошибку:

Ошибка 1. Неверный файл Resx.Не удалось загрузить тип Serialisation.Harness.Blob, Serialisation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, который используется в файле .RESX.Убедитесь, что в ваш проект добавлены необходимые ссылки.Строка 129, позиция 5....

Теперь действительно странно то, что перезапуск Visual Studio приводит к исчезновению ошибки и коду, который работает, но затем после, казалось бы, случайного количества сборок (во время которых указанный код нет изменил) он снова сломается.

Вы видите, что я делаю неправильно/упускаю?

Спасибо заранее,

Мне тоже

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);
        }

    }

}
Это было полезно?

Решение

Прежде всего, Serializable атрибут не используется для сериализации дизайнера.При сериализации объектов конструктор выполняет сериализацию в файл ресурсов, если не знает, как записать его в код дизайнера.Это записывает его в resx как большой двоичный объект, используя InstanceDescriptor для конструктора по умолчанию типа объекта (при этом теряются все значения свойств, которые вы также можете включить).Это то, что происходит для Blobs свойство, поскольку дизайнер не очень хорошо сериализует общие списки (хотя он знает, как сериализовать массивы).

Чтобы сохранить информацию внутри этих постоянных объектов, вам необходимо создать TypeConverter который указывает другой конструктор в InstanceDescriptor (тот, который на самом деле принимает некоторое состояние для описания свойств, например, ваше Blobs свойство).Например, если вы добавили конструктор в свой BasicComponent тип, который принимает IEnumerable<Blob>, тогда вы сможете получить InstanceDescriptor этому конструктору, передавая массив Blobs (вы бы создали новый List<Blob> вокруг этого в конструкторе).Поскольку дизайнер знает, как сохранить InstanceDescriptor для кода, и поскольку он знает, как сохранять массивы в коде, он затем добавит это в ваш код дизайнера, а не в файл resx.

Вы также можете реализовать CodeDomSerializer чтобы указать код, используемый для описания вашего экземпляра, который дизайнер может использовать для сохранения вашего объекта в коде дизайнера, а не в resx.

Конвертер типов

Чтобы использовать подход преобразователя типов, вы можете сделать что-то вроде этого:

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;
    }
}

Обратите внимание, что вам может потребоваться написать преобразователь типов для Blob тип тоже.Чтобы присоединить преобразователь типов к типу, просто объявите TypeConverter атрибут класса, который конвертирует преобразователь типов, т.е.BasicConverter для примера выше.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top