.NETCore XmlSerializer error - c#

I have an application runnin .NETFramework 4.6.1, using xml serialization for abstract classes and inherited types, with approach almost identical to this XML Serialization and Inherited Types, and it works great. But after porting application to UWP .NETCore I've encountered a strange exception. Here is a simple example to reproduce it.
public class ClassToSerialize
{
[XmlElement(Type = typeof(CustomSerializer<AnotherOne>))]
public AnotherOne anotherOne;
public ClassToSerialize()
{
}
}
public abstract class AnotherOne
{
public AnotherOne()
{
}
}
public class CustomSerializer<TType> : IXmlSerializable
{
public CustomSerializer()
{
}
public CustomSerializer(TType data)
{
m_data = data;
}
public static implicit operator CustomSerializer<TType>(TType data)
{
return data == null ? null : new CustomSerializer<TType>(data);
}
public static implicit operator TType(CustomSerializer<TType> obj)
{
return obj.m_data;
}
private TType m_data;
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
}
public void WriteXml(XmlWriter writer)
{
}
}
And creating XmlSerializer for this type
XmlSerializer sr = new XmlSerializer(typeof(ClassToSerialize));
causes exception
System.InvalidOperationException: TestApp.AnotherOne, TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null is not assignable from TestApp.CustomSerializer`1[[TestApp.AnotherOne, TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
Same code works in .netframework app. Did they changed something in .netcore or am i missing something?

Your issue linked with type that represented serialization type. For universal App their must be derived from (as I can see)
For example:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
XmlSerializer sr = new XmlSerializer(typeof(ClassToSerialize));
var demo = new DemoChild();
var ser = new ClassToSerialize {anotherOne = demo};
var stream = new MemoryStream();
sr.Serialize(stream, ser);
}
}
public class ClassToSerialize
{
[XmlElement(Type = typeof(DemoChild))]
public AnotherOne anotherOne;
public ClassToSerialize()
{
}
}
public abstract class AnotherOne : IXmlSerializable
{
protected AnotherOne()
{
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
}
public void WriteXml(XmlWriter writer)
{
}
}
public class DemoChild: AnotherOne
{
}
Using generic serializer is important for you? I've tested on universal App unit test and all work correctly.
P.s. Type - The of an object derived from the member's type. From documentation

Use XAML serializer:
nuget> Install-Package Portable.Xaml
public class ClassToSerialize
{
public AnotherOne anotherOne { get; set; }
public ClassToSerialize()
{
}
}
public abstract class AnotherOne
{
public AnotherOne()
{
}
}
public class ContainerOne : AnotherOne
{
public uint placeholder = 0xdeadcafe;
}
public void Test()
{
ClassToSerialize obj = new ClassToSerialize();
obj.anotherOne = new ContainerOne();
//or FileStream..
using (MemoryStream ms = new MemoryStream())
{
Portable.Xaml.XamlServices.Save(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
ClassToSerialize obj2 = Portable.Xaml.XamlServices.Load(ms) as ClassToSerialize;
}
}

Try downloading System.Xml.XmlSerializer from Nuget. I think it is developed in .NETStandard
here lists all versions of .NET Standard and the platforms supported

Related

Using method from Class to change class

I wanted to create a class and use a method from the initialized class to change the property values of the calling instance. Somehow I have a knot in my brain and there seems to be a basic thinking error of mine. Maybe someone can help me figure it out.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load();
Console.WriteLine(myZoo.ZooName);
}
}
and the Zoo-Class:
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load()
{
Zoo myZoo = this;
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
The JSON part works fine, but as soon as the Load()-method comes to an end the myZoo/this is set to NULL. Is there any possibility to use 'this' to modify the property values of the calling class instance?
You probably want to make a factory method on your class instead. This function will return a new instance of Zoo with the data from your json file.
Like this:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Init()
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
var myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
return myZoo;
}
}
}
In your Initialize function you can now create an instance like this:
private void Initialize()
{
var myZoo = Zoo.Init();
Console.WriteLine(myZoo.ZooName);
}
other way out.you can use ref keyword for the same.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load(ref myZoo);
Console.WriteLine(myZoo.ZooName);
}
}
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load(ref Zoo myZoo)
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
You cannot set the this pointer. There also is no assignment operator in C# to overload.
You could copy all properties from your loaded zoo object into the this object.
A more common approach is to have a static factory method to do this for you:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Load(string file)
{
using (StreamReader reader = File.OpenText(file))
{
JsonSerializer serializer = new JsonSerializer();
return (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
Later call it like this:
Zoo z = Zoo.Load(#"C:\Areas.json");

DataContractJsonSerializer ; ISerializable GetObjectData called with .NET but not with mono

Below is a simplified example of what I'm trying to accomplish.
I have a class DoNotSerializeMe which is part of an external library and cannot be serialized.
using System;
namespace CustomJsonSerialization
{
public class DoNotSerializeMe
{
public string WhyAmIHere;
public DoNotSerializeMe(string mystring)
{
Console.WriteLine(" In DoNotSerializeMe constructor.");
WhyAmIHere = "( constructed with " + mystring + " )";
}
}
}
I also have a class SerializeMe which has a member of type DoNotSerializeMe. I can make this class implement ISerializable and get around the issue of DoNotSerializeMe not being serializable by pulling data and calling the constructor.
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace CustomJsonSerialization
{
[System.Serializable]
public class SerializeMe : ISerializable
{
public DoNotSerializeMe SerializeMeThroughISerializable;
public SerializeMe(string mystring)
{
SerializeMeThroughISerializable = new DoNotSerializeMe(mystring);
}
protected SerializeMe(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine(" In SerializeMe constructor (ISerializable)");
SerializeMeThroughISerializable = new DoNotSerializeMe(info.GetString("SerializeMeThroughISerializable"));
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
System.Console.WriteLine(" In SerializeMe.GetObjectData()");
info.AddValue("SerializeMeThroughISerializable",
"( deserialized through getObjectData " +
SerializeMeThroughISerializable.WhyAmIHere + " )");
}
}
}
Below is a short program that serializes and deserializes the object:
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace CustomJsonSerialization
{
public class Program
{
public static void Main(string[] args)
{
SerializeMe serializeme = new SerializeMe("initial");
Console.WriteLine("I created it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere);
Console.WriteLine();
MemoryStream memstream = new MemoryStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SerializeMe));
serializer.WriteObject(memstream, serializeme);
Console.WriteLine("I serialized it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere);
Console.WriteLine();
Console.WriteLine("Json:");
Console.WriteLine(Encoding.ASCII.GetString(memstream.ToArray()));
Console.WriteLine();
memstream.Seek(0, SeekOrigin.Begin);
SerializeMe anotherSerializeMe = (SerializeMe)serializer.ReadObject(memstream);
Console.WriteLine("I deserialized it: {0}", anotherSerializeMe.SerializeMeThroughISerializable.WhyAmIHere);
}
}
}
When running through .NET (4.5), I get the following:
In DoNotSerializeMe constructor.
I created it: ( constructed with initial )
In SerializeMe.GetObjectData()
I serialized it: ( constructed with initial )
Json:
{"SerializeMeThroughISerializable":"( deserialized through getObjectData ( constructed with initial ) )"}
In SerializeMe constructor (ISerializable)
In DoNotSerializeMe constructor.
I deserialized it: ( constructed with ( deserialized through getObjectData ( constructed with initial ) ) )
The serializer called the ISerializable construction and the GetObjectData when serializing / deserializing (as expected). I never serialize or deserialize the DoNotSerializeMe object directly.
However, when running the same build through mono (tried 3.10.0 and 4.0.2), I get the following:
In DoNotSerializeMe constructor.
I created it: ( constructed with initial )
I serialized it: ( constructed with initial )
Json:
{"SerializeMeThroughISerializable":{"WhyAmIHere":"( constructed with initial )"}}
I deserialized it: ( constructed with initial )
Obviously, if DoNotSerializeMe was truly not serializable, this would lead to an error.
Is there an elegant way to get around this without using Json.NET? I'm not sure why mono isn't behaving the same way as .NET.
I'm going to suggest an alternative approach: use a surrogate data transfer type to serialize your DoNotSerializeMe class. One way to do this is with Data Contract Surrogates. But are data contract surrogates supported on mono? The current version of the source code shows that they are, but this version shows it as [MonoTODO], so I cannot guarantee that your version of mono has a working implementation for DataContractJsonSerializer.DataContractSurrogate.
However, a manual surrogate property will always work. For instance, the following SerializeMe type can be serialized and serialized even though its DoNotSerializeMe member cannot be serialized directly:
public class DoNotSerializeMe
{
public readonly string WhyAmIHere;
readonly bool ProperlyConstructed; // data contract serializer does not call the constructor
public DoNotSerializeMe(string mystring)
{
Console.WriteLine(string.Format(" In DoNotSerializeMe constructor, mystring = \"{0}\"", mystring));
WhyAmIHere = mystring;
ProperlyConstructed = true;
}
public void Validate()
{
if (!ProperlyConstructed)
throw new InvalidOperationException("!ProperlyConstructed");
}
}
public class SerializeMe
{
[IgnoreDataMember]
public DoNotSerializeMe CannotBeSerializedDirectly;
public DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate
{
get
{
if (CannotBeSerializedDirectly == null)
return null;
return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere };
}
set
{
if (value == null)
CannotBeSerializedDirectly = null;
else
CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate);
}
}
public string SomeOtherField { get; set; }
}
public class DoNotSerializeMeSurrogate
{
public string WhyAmIHereSurrogate { get; set; }
}
Using this approach looks simpler than implementing ISerializable since all the members other than CannotBeSerializedDirectly continue to be serialized automatically. Note the use of [IgnoreDataMember]. It prevents the CannotBeSerializedDirectly member from being included in the implicit data contract for the class.
If you would prefer your surrogate to be private, or need to control the surrogate member names, you will need to give the containing type an explicit data contract:
[DataContract]
public class SerializeMe
{
[IgnoreDataMember]
public DoNotSerializeMe CannotBeSerializedDirectly;
[DataMember]
DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate
{
get
{
if (CannotBeSerializedDirectly == null)
return null;
return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere };
}
set
{
if (value == null)
CannotBeSerializedDirectly = null;
else
CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate);
}
}
[DataMember]
public string SomeOtherField { get; set; }
}
[DataContract]
class DoNotSerializeMeSurrogate
{
[DataMember]
public string WhyAmIHereSurrogate { get; set; }
}

Cascading the effect of an attribute to overridden properties in child classes

Is it possible to mark a property in base class with some attribute that remains effective in child classes too?
Question might be very specific to Serialization, but I definitely think there can be other uses as well.
Consider the following code:
using System;
using System.IO;
using System.Xml.Serialization;
namespace Code.Without.IDE
{
[Serializable]
public abstract class C1
{
[XmlIgnore]
public abstract bool IsValid_C1 { get; set;}
}
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
public override bool IsValid_C1 { get; set;}
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
public static class AbstractPropertiesAttributeTest
{
public static void Main(string[] args)
{
C2 c2 = new C2();
using(MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = new XmlSerializer(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
}
}
Above code returns:
------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe
<?xml version="1.0"?>
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IsValid_C2>false</IsValid_C2>
<IsValid_C1>true</IsValid_C1>
</C2>
------ Process returned 0
I thought IsValid_C1 will be ignored, though it is not so. Is there any way of achieving this other than marking the property as protected?
Edit: A quick code to show that XmlIgnore attibute is being inherited.
http://ideone.com/HH41TE
I don't believe there is a way to inherit the attribute since you override the base class property. You would need to decorate the IsValid_C1 of C2 with XmlIgnore:
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
[XmlIgnore]
public override bool IsValid_C1 { get; set; }
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
I will offer a different view of this question. Maybe you just used those properties as an example and want to have severall properties to be cascaded. But i think that this may be a good time to think about the inheritance model proposed.
Basicly you can use regular inheritance or think about some Design Pattern, that can not just solve you issue related to the serialization, but may offer you some more "loose coupling" in you application, making it in a more component model and allowwing each class to deal only with what is concern, this way you can re-use lots of stuff and make your life easier.
Based on that thinking im providing you a sample of the Decorator Design Pattern mixed with the Strategy Design Pattern. If i were developing classes like the ones on your sample, this is how i would do it:
/// <summary>
/// The interface for validation strategy (since we are using interface, there is no need for another abstract class)
/// </summary>
public interface IValidation
{
bool IsValid { get; set; }
}
/// <summary>
/// The decorator (it dont need to be abstract) that has the serializable properties
/// </summary>
[Serializable]
public class ValidatableDecorator : IValidation
{
protected IValidation instance;
public ValidatableDecorator()
{
Init();
}
public ValidatableDecorator(IValidation instance)
{
Init();
}
protected virtual void Init() { }
public void Set(IValidation instance)
{
this.instance = instance;
}
[XmlIgnore]
public bool IsValid
{
get
{
return instance.IsValid;
}
set
{
instance.IsValid = value;
}
}
}
Then you need to implement some classes that have the logic of the strategy Pattern, like this:
public class BossValidatorImplementation : IValidation
{
public bool IsValid
{
get
{
return false; ;
}
set
{
throw new InvalidOperationException("I dont allow you to tell me this!");
}
}
}
public class EasyGoingValidator : IValidation
{
public bool IsValid { get; set; }
}
Now that we have the logic separated from the class, we can inherit from the decorators, choosing wich strategy they use to the IsValid field, like this:
public class ChildWithBossValidation : ValidatableDecorator
{
protected ChildWithBossValidation(IValidation instance)
: this()
{
Init();
}
public ChildWithBossValidation()
: base(new BossValidatorImplementation())
{
Init();
}
protected override void Init()
{
Name = "I'm the boss!";
Sallary = 10000d;
}
public string Name { get; set; }
public double Sallary { get; set; }
}
public class ChildWithEasyGoingValidation : ValidatableDecorator
{
public ChildWithEasyGoingValidation()
: base(new EasyGoingValidator())
{
}
protected ChildWithEasyGoingValidation(IValidation instance)
: this()
{
}
protected override void Init()
{
Name = "Do as you please... :) ";
}
public string Name { get; set; }
}
This is the code to show that the solution works:
public static void Main(string[] args)
{
var boos = new ChildWithBossValidation();
var coolGuy = new ChildWithEasyGoingValidation();
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(boos.GetType());
ser.Serialize(ms, boos);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.WriteLine("-------------");
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(coolGuy.GetType());
ser.Serialize(ms, coolGuy);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.ReadKey();
}
The result is:
{<?xml version="1.0"?>
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>I'm the boss!</Name>
<Sallary>10000</Sallary>
</ChildWithBossValidation>-------------------<?xml version="1.0"?>
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Do as you please... :) </Name>
</ChildWithEasyGoingValidation>}
So, maybe this does not answer how to cascade the Attribute in this case (because you can easily do it by creating your own attribute(marking to allow inheritance) and then implementing some code to SerializeXML). This is just another option that can improve overall architecture of solutions using Design Pattern. But this solve this particular issue also :)
A needed behaviour can be achieved using classes XmlAttributeOverrides and XmlAttributes. I've written helper method for XmlSerializer creation:
public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t)
{
XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute));
if (xmlIgnoreAttribute == null)
continue;
XmlAttributes xmlAttributes = new XmlAttributes();
xmlAttributes.XmlIgnore = true;
xmlOverrides.Add(t, prop.Name, xmlAttributes);
}
return new XmlSerializer(t, xmlOverrides);
}
The Main method became:
public static void Main(string[] args)
{
C2 c2 = new C2();
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
It appears this feature is broken in C#.
You could write an attribute which through reflection will bring down the attributes for you. Pretty straight forward if you understand reflection.

Serializing IEnumerable Containing Derived classes: Circular Reference Issue

I am trying to serialize IEnumerable using the following code. I am getting the following exception.
There was an error generating the XML document. "A circular reference was detected while serializing an object of type DBML_Project.FixedBankAccount."}.
Why does this error come? How to correct it?
Note: I am already using InheritanceMapping attribute.
public class BankAccountAppService
{
public RepositoryLayer.ILijosBankRepository AccountRepository { get; set; }
public void FreezeAllAccountsForUser(int userId)
{
IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
foreach (DBML_Project.BankAccount acc in accounts)
{
acc.Freeze();
}
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
System.Xml.XPath.XPathNavigator nav = xmlDoc.CreateNavigator();
using (System.Xml.XmlWriter writer = nav.AppendChild())
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(List<DBML_Project.BankAccount>));
ser.Serialize(writer, accounts);
}
}
}
namespace DBML_Project
{
[System.Xml.Serialization.XmlInclude(typeof(FixedBankAccount))]
[System.Xml.Serialization.XmlInclude(typeof(SavingsBankAccount))]
public partial class BankAccount
{
//Define the domain behaviors
public virtual void Freeze()
{
//Do nothing
}
}
public class FixedBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenFA";
}
}
public class SavingsBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenSB";
}
}
}
Autogenerated Class using LINQ to SQL
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged
Use the data contract serializer instead of the xmlserializer:
http://jameskovacs.com/2006/11/18/going-around-in-circles-with-wcf/

.NET Serializable entity

I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
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);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
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;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with 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);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
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 how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
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");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
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.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).

Categories

Resources