.NET可序列化实体

本文关键字:实体 序列化 NET | 更新日期: 2023-09-27 17:59:20

我需要使我的所有实体都可序列化。所以我在考虑一个带有备份和恢复方法的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);
    }
}

.NET可序列化实体

更常见的模式是不让对象负责序列化/反序列化它们自己;相反,请使用外部序列化程序:

var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);

Edit:序列化的一种工作方式是使用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放在所有类型上。任何无法序列化的字段(因为它不是结构,或者没有标记为[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);
    }
}

编辑:我提到的方式是一种相当标准和可接受的方式。如果你想冒险进入hackdom,你可以按照我提到的方式反序列化对象,然后使用反射将现有对象上的每个字段设置为反序列化对象的值。

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));
      }
   }
}
public IEntidadBase Restore()
{
    return (IEntidadBase)bf.Deserialize(ms);
}

@jacklondon您将如何执行EntitySerializer方法?

您可以使用执行序列化过程http://www.servicestack.net/StackService.用于干净实体的文本模块。您不需要任何ms方式的属性(可序列化/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");
        }
    }

我不一定建议这样做,但对于可以使用创建新实例的序列化来持久化和恢复其自身状态的对象,这里有一种模式:

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

请注意,只有当序列化程序支持非公共类时,这才有效。最糟糕的情况是,必须将嵌套类公开,这很难看,但不会影响封装(因为实例是私有的)。