.NET Сериализуемая сущность - PullRequest
1 голос
/ 15 июня 2011

Мне нужно сделать все мои объекты сериализуемыми. Поэтому я думал о BaseEntity с методом резервного копирования и восстановления. Но при восстановлении я не могу переопределить объект с сохраненным, потому что this только для чтения.

Любое решение или какой-то другой способ получить сериализуемые объекты?

Мой код:

internal class BaseEntity
{
    private MemoryStream ms = new MemoryStream();
    private BinaryFormatter bf = new BinaryFormatter();

    public void Backup()
    {
        bf.Serialize(ms, this);
    }

    public void Restore()
    {
        this = (BaseEntity)bf.Deserialize(ms);
    }
}

Ответы [ 4 ]

2 голосов
/ 15 июня 2011

Более распространенный шаблон - не брать на себя ответственность за сериализацию / десериализацию ваших объектов; вместо этого используйте внешний сериализатор:

var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;

serializer.WriteObject(stream, yourObj);

var restoredObj = serializer.ReadObject(stream);
1 голос
/ 15 июня 2011

Редактировать: один из способов сериализации может работать - это использовать System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (или другую реализацию IFormatter).Для сериализации объекта вы передаете объект и поток.Для десериализации объекта вы передаете поток (расположенный в начале ваших сериализованных данных), и он возвращает сериализованный объект и все его зависимости.

public static class EntityBackupServices
{
   public static MemoryStream Backup (BaseEntity entity)
   {
      var ms = new MemoryStream();
      Serialize (ms, entity);
      ms.Position = 0;
      return ms;
   }
   public static void Serialize (Stream stream, BaseEntity entity)
   {
      var binaryFormatter = new BinaryFormatter();
      binaryFormatter.Serialize (stream, entity);
   }
   public static BaseEntity Restore (Stream stream)
   {
      var binaryFormatter = new BinaryFormatter();
      var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
      return entity;
   }
}

Одна вещь, которую форматировщик не делает (хотякласс FormatterServices позволяет) изменять существующие объекты.Поэтому вы, вероятно, не хотите иметь метод экземпляра с именем Deserialize.Вы не можете сделать это: new LionEntity().Deserialize (), где он заменяет поля существующего экземпляра.

Примечание: Вам нужно поставить Serializable поверх всехваши типы.Любые поля, которые нельзя сериализовать (поскольку они не являются структурой или не помечены как [Сериализуемые], должны быть помечены NonSerialized .

// A test object that needs to be serialized.
[Serializable()]        
public class BaseEntity
{
    public int member1;
    public string member2;
    public string member3;
    public double member4;

    // A field that is not serialized.
    [NonSerialized()] public MyRuntimeType memberThatIsNotSerializable; 

    public TestSimpleObject()
    {
        member1 = 11;
        member2 = "hello";
        member3 = "hello";
        member4 = 3.14159265;
        memberThatIsNotSerializable = new Form ();
    }

    public MemoryStream Backup ()
    {
       return EntityBackupServices.Backup (this);
    }
}

Редактировать:способ, который я упомянул, является довольно стандартным и общепринятым. Если вы хотите заняться хакдомом, вы можете десериализовать объект так, как я упомянул, а затем использовать отражение, чтобы установить для каждого поля вашего существующего объекта значение десериализованногообъект.

public class BaseEntity
{
   void Restore(Stream stream)
   {
      object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
      if (deserialized.GetType () != this.GetType ())
         throw new Exception();
      foreach (FieldInfo fi in GetType().GetFields())
      {
         fi.SetValue(this, fi.GetValue (deserialized));
      }
   }
}
1 голос
/ 15 июня 2011
public IEntidadBase Restore()
{
    return (IEntidadBase)bf.Deserialize(ms);
}

@ jacklondon, как бы вы применили методы EntitySerializer?

Процесс сериализации можно выполнить с помощью http://www.servicestack.net/ модуля StackService.Text для чистых объектов. Вам не нужен какой-либо атрибут (serializable / datacontract) в виде мс.

 public class EntityFoo
    {
        public string Bar { get; set; }

        public EntityFoo (string bar)
        {
            Bar = bar;
        }
    }

    public class EntityDumper //and the EntitySerializer
    {
        public static string Dump<T> (T entity)
        {
            return new TypeSerializer<T> ().SerializeToString (entity);
        }

        public static T LoadBack<T> (string dump)
        {
            return new TypeSerializer<T> ().DeserializeFromString (dump);
        }
    }



    public class dump_usage
    {
        public void start ()
        {
            string dump = EntityDumper.Dump (new EntityFoo ("Space"));

            EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
            Debug.Assert (loaded.Bar == "Space");
        }
    }
0 голосов
/ 15 июня 2011

Я не обязательно рекомендую это, но вот один шаблон для объекта, который может сохраняться и восстанавливать свое собственное состояние, используя сериализацию, которая создает новые экземпляры:

public sealed class MyClass
{
    private Data _data = new Data();

    //Properties go here (access the public fields on _data)

    public void Backup()
    {
        //Serialize Data
    }

    public void Restore()
    {
        //Deserialize Data and set new instance
    }

    private sealed class Data
    {
        //Public fields go here (they're private externally [because Data is private], but public to MyClass.)
    }
}

Обратите внимание, что это работает, только если ваш сериализатор поддерживает закрытые классы. В худшем случае, вы должны сделать вложенный класс общедоступным, что некрасиво, но не вредит инкапсуляции (поскольку экземпляр является частным).

...