I go to the MSDN to search the singleton serialization, and find the source code http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationinfo.aspx
but I had problems when I changed some part of the code. I divide it into two program : serialization and deserialization. Below is the Main function of the two(other classes are in the msdn documentation, link is at the second line).
Serialization program is below:
public static void Main()
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
try
{
// Construct a BinaryFormatter and use it
// to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
// Create an array with multiple elements refering to
// the one Singleton object.
Singleton[] a1 = { Singleton.GetSingleton(), Singleton.GetSingleton() };
a1[0].SomeNumber = 555;
formatter.Serialize(fs, a1);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
Deserialization program:
public static void Main()
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
// Construct a BinaryFormatter and use it
// to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
Singleton[] a2 = (Singleton[]) formatter.Deserialize(fs);
// This displays "True".
Console.WriteLine(a2[0].SomeNumber);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
After I executed the two program, the console didn't print 555 but still 123, why? I can't figure it out and got stuck in it for the whole day, can anybody help me ?
I believe you will find many answers on this documentation : IObjectReference
Serializing Singletons never is really easy. But do you really have to serialize them, and then deserialize them ?
Here is a code sample from the MSDN link I provided :
using System;
using System.Web;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Security.Permissions;
// There should be only one instance of this type per AppDomain.
[Serializable]
[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
[AspNetHostingPermission(SecurityAction.LinkDemand,
Level=AspNetHostingPermissionLevel.Minimal)]
public sealed class Singleton : ISerializable
{
// This is the one instance of this type.
private static readonly Singleton theOneObject = new Singleton();
// Here are the instance fields.
private string someString_value;
private Int32 someNumber_value;
public string SomeString
{
get{return someString_value;}
set{someString_value = value;}
}
public Int32 SomeNumber
{
get{return someNumber_value;}
set{someNumber_value = value;}
}
// Private constructor allowing this type to construct the Singleton.
private Singleton()
{
// Do whatever is necessary to initialize the Singleton.
someString_value = "This is a string field";
someNumber_value = 123;
}
// A method returning a reference to the Singleton.
public static Singleton GetSingleton()
{
return theOneObject;
}
// A method called when serializing a Singleton.
[SecurityPermissionAttribute(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(
SerializationInfo info, StreamingContext context)
{
// Instead of serializing this object,
// serialize a SingletonSerializationHelp instead.
info.SetType(typeof(SingletonSerializationHelper));
// No other values need to be added.
}
// Note: ISerializable's special constructor is not necessary
// because it is never called.
}
[Serializable]
[PermissionSet(SecurityAction.Demand, Name="FullTrust")]
[SecurityPermissionAttribute(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.SerializationFormatter)]
[AspNetHostingPermission(SecurityAction.LinkDemand,
Level=AspNetHostingPermissionLevel.Minimal)]
internal sealed class SingletonSerializationHelper : IObjectReference
{
// This object has no fields (although it could).
// GetRealObject is called after this object is deserialized.
public Object GetRealObject(StreamingContext context)
{
// When deserialiing this object, return a reference to
// the Singleton object instead.
return Singleton.GetSingleton();
}
}
class App
{
[STAThread]
static void Main()
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
try
{
// Construct a BinaryFormatter and use it
// to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
// Create an array with multiple elements refering to
// the one Singleton object.
Singleton[] a1 = { Singleton.GetSingleton(), Singleton.GetSingleton() };
// This displays "True".
Console.WriteLine(
"Do both array elements refer to the same object? " +
(a1[0] == a1[1]));
// Serialize the array elements.
formatter.Serialize(fs, a1);
// Deserialize the array elements.
fs.Position = 0;
Singleton[] a2 = (Singleton[]) formatter.Deserialize(fs);
// This displays "True".
Console.WriteLine("Do both array elements refer to the same object? "
+ (a2[0] == a2[1]));
// This displays "True".
Console.WriteLine("Do all array elements refer to the same object? "
+ (a1[0] == a2[0]));
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
}
Okay, so first, to answer your main question:
Your implementation for ISerializable.GetObjectData is using IObjectReference.GetRealObject to fetch a reference to an object already existing on your class loader heap. In other words, no deserialization isn't creating an object and using the setters to populate the serialized data for you - it's just reaching into memory and giving you the instance you modified to '555'.
This works in the sample because everything's happening in the same process - your "deserialization" simply gets a reference to the Singleton instance that you modified earlier. When you split off the deserialize into another program, it fetches the only 'Singleton' reference it knows - the static instance assigned to theOneObject, which was initialized with '123'.
So here's how I would do what you want:
Make your TaskManager a singleton if you want (although a static class seems sufficient), but do not serialize the singleton. Instead, store your state (all your tasks, etc) in another TaskList object that is a static and immutable field of your TaskManager, that is deserialized inside a static constructor or threadsafe singleton initialization. Don't expose the TaskList reference directly - let methods on your TaskManager class control access to it - AddTask, DeleteTask, GetTaskStatus, etc.
Your data's unique, but it's taken care of in a somewhat nicer, easier to implement manner.
Related
I'm trying to convert a collection of multiple types (using a generic class that implements an interface to enable storage) into XML.
That's the short explanation of what I'm trying to do. Below is a description of what I've tried thus far and where I'm currently stuck.
The current implementation is a dictionary that can take a string as a key and any type (stored as the interface) as a value. (Technically I've got a parallel array structure going on right now because that's easier to serialize than a dictionary but for the below example I've used a dictionary cause it reduces some guff so just pretend it works ;) )
Sadly, you cannot serialze interfaces.
I know IXmlSerializable exists but I get this error when I try having that as the value:
InvalidOperationException: System.Xml.Serialization.IXmlSerializable cannot be serialized because it does not have a parameterless constructor.
Rethrow as InvalidOperationException: Cannot serialize member 'GenericDictionary.A_values' of type 'System.Xml.Serialization.IXmlSerializable[]', see inner exception for more details.
(A_values is a IXmlSerializable Array, also am happy to post the inner explaination but it's a bit long)
Now I know that IXmlSerializable is supposed to be implemented in a class and then you would stored that class in your collection, however I cannot store the class in the dictionary because it requires a type and that's what I'm trying to avoid.
Any guidance would be useful.
Here's more or less the code
using System;
using System.Xml;
using System.Xml.Serialization;
[XmlRoot("GenericDictionary")]
public class GenericDictionary
{
[XmlArray("parameters")]
private Dictionary<string, IGenericParameter> genericDictionary = new Dictionary<string, IGenericParameter>();
public GenericDictionary(){}
public T GetParameter<T>(string _key)
{
// Cast the interface to a concrete implementation and access the parameter
GenericParameter paramToGet = (GenericParameter)genericDictionary[_key];
return paramToGet.GetParam;
}
public void AddParameter<T>(string _key, T _value)
{
// Add a new GenericParameter (which will be stored as its interface but still accessible via casting)
genericDictionary.Add(_key, new GenericParameter(_value));
}
}
// This exists to allow us to store GenericParameter in the dictionary without a type passed in
public interface IGenericParameter{}
[XmlRoot("parameter")]
public class GenericParameter<T> : IGenericParameter
{
[XmlAttribute("value")]
private T _param;
public T GetParam { get { return _param; } }
// XML Serializer needs an empty constructor
public GenericParameter(){}
public GenericParameter(T _value)
{
_param = _value;
}
}
public class Writer
{
GenericDictionary testDictionary;
public void TestWrite(string _filePath)
{
testDictionary = new GenericDictionary();
testDictionary.AddParameter<float>("TestFloat", 0.5f);
testDictionary.AddParameter<int>("TestInt", 16);
XmlSerializer serializer = new XmlSerializer(typeof(GenericDictionary));
FileStream fs = new FileStream(_filePath, FileMode.Create);
serializer.Serialize(fs, testDictionary);
fs.close();
}
}
I need to serialize any type of object. In order to serialize an object, it must have a Serializable attribute. So I need to add that attribute to any object at runtime. I think it's only possible by creating a new type using System.Reflection.
Here's a simple method that tests whether the object is serializable (has the Serializable attribute) or not.
bool IsObjectSerializable(object obj)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
// If it's not serializable (aka doesn't have the Serializable attribute) it will thrown an exception.
formatter.Serialize(stream, obj);
return true;
}
catch(SerializationException)
{
return false;
}
}
I have a serializable and a non-serializable class:
[Serializable]
class SerializableTestObject
{
}
class TestObject
{
}
void Main()
{
Console.WriteLine(IsObjectSerializable(new SerializableTestObject())); // prints true
Console.WriteLine(IsObjectSerializable(new TestObject())); // prints false
dynamic modifiedTestObject = AddAttributeToObject<SerializableAttribute>(new TestObject());
Console.WriteLine(IsObjectSerializable(modifiedTestObject)); // should print true
}
What do I need to write in AddAttributeToObject?
I've done some research, but I found very little resources on this topic, and most people just say it's hard to do and stuff like that.
I need to make a copy of a MyGame class and use it in my simulation for game trials before I select a move to play.
For example :
public class MyGame
{
private int Start;
private Board board;
//Constructor
public void Play()
{
//play game
}
public object Clone()
{
}
}
public class Board
{
private int Count;
//Constructor
//Some methods and properties
public object Clone()
{
}
}
Writing code for the method Clone() I have tried
MemberwiseClone()
(Board) this.MemberwiseClone()
Board b = (Board) this.Board
I have read alot of articles and forums about this topic. The answer most people
use is Deep cloning objects in C#, I tried samples with respect to my project but I still
get my simulation modifying the original object (MyGame Class) and not the copy.
Here I have an example for a deep copy, which deeply copies all reference type objects that are used with a copy constructor:
public sealed class MyGame
{
private int start;
private Board board;
public MyGame(MyGame orig)
{
// value types - like integers - can easily be
// reused
this.start = orig.start;
// reference types must be clones seperately, you
// must not use orig.board directly here
this.board = new Board(orig.board);
}
}
public sealed class Board
{
private int count;
public Board(Board orig)
{
// here we have a value type again
this.count = orig.count;
// here we have no reference types. if we did
// we'd have to clone them too, as above
}
}
I think your copy might be somehow shallow and re-use some references (like for instance this.board = orig.board instead of creating a new board). This is a guess though, as I can't see your cloning implementation.
Furthermore, I used copy constructors instead of implementing ICloneable. The implementation is almost the same. One advantage though is that you simplify dealing with subclasses:
Suppose you had a MyAwesomeGame : MyGame, not overriding MyGame.Clone. What would you get from myAwesomeGame.Clone()? Actually, still a new MyGame because MyGame.Clone is the method in charge. One may carelessly expect a properly cloned MyAwesomeGame here, however. new MyGame(myAwesomeGame) still copies somehow incompletely, but it's more obvious. In my example I made the classes sealed to avoid this failures. If you can seal them, there's good change it will make your life simpler.
Implementing ICloneable is not recommended in general, see Why should I implement ICloneable in c#? for more detailed and general information.
Here I have an ICloneable approach anyway, to make things complete and enable you to compare and contrast:
public class MyGame : ICloneable
{
private int start;
private Board board;
public object Clone()
{
var copy = new MyGame();
copy.start = this.start;
copy.board = (Board)this.board.Clone();
return copy;
}
}
public class Board : ICloneable
{
private int count;
public object Clone()
{
var copy = new Board();
copy.count = this.count;
return copy;
}
}
The simplest and most reliable way to implement deep cloning is to serialize, and then deserialize your objects. This can have a large performance cost associated with it. Consider classes from this namespace for serialization http://msdn.microsoft.com/en-us/library/System.Xml.Serialization.aspx
Deep cloning requires recursively creating a new instance of every property that is not a value type. Cloning MyGame would require a new instance of MyGame and a new instance of Board, both populated with the same Start and Count values as their originals. This is fiddly and a nightmare to maintain. As you can guess, it is not an automatic process out of the box but it can be, using reflection (which is how the xml serialization above works.
MemberwiseClone only creates a new instance of the object you called it on - all references remain the same.
MemberwiseClone() creates a stupid shallow clone of each member of an object. This works fine when members are value types but in case of reference types it fails because it'll clone pointers and not pointed objects.
Starting from your code a memberwise clone is something like this:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start; // Copied (cloned) because value type
cloned.Board = this.Board; // This is not a copy, just a reference!
}
A better solution for a deep clone would be to implement ICloneable (for example, otherwise a copy constructor approach is also good) for each reference type, let's suppose Board is cloneable too:
public object Clone()
{
MyGame cloned = new MyGame();
cloned.Start = this.Start;
cloned.Board = (Board)this.Board.Clone();
}
Please note that in your example Board can implement Clone() using MemberwiseClone() because its members are all value types.
If you can't manage this (for example because code is not accesible) or you need a quick/dirty solution you may consider to user serializaiton (in memory). Which serializer is a big question, each one has some limitations (about what's serialized and how). For example XML serializer won't serialize private fields (it won't serialize fields at all). Faster one is binary formatter but you need to mark each class with a proper attribute.
Change according serializer you prefer (according to your requirements), in this case I assume you marked MyGame and Board as [Serializable] for the quick binary serialization:
public object Clone()
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
Try this
public static T DeepCopy<T>(this T obj)
{
T result;
var serializer = new DataContractSerializer(typeof(T));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
ms.Position = 0;
result = (T)serializer.ReadObject(ms);
ms.Close();
}
return result;
}
I have two extension methods that I use to achieve this. Demo code below:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace SimpleCloneDemo
{
public class Program
{
public static void Main(string[] args)
{
var person = new Person { Id = 1, FirstName = "John", Surname = "Doe" };
var clone = person.Clone();
clone.Id = 5;
clone.FirstName = "Jane";
Console.WriteLine(#"person: {0}", person);
Console.WriteLine(#"clone: {0}", clone);
if (Debugger.IsAttached)
Console.ReadLine();
}
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public override string ToString()
{
return string.Format("Id: {0}, Full Name: {1}, {2}", Id, Surname, FirstName);
}
}
public static class ObjectExtensions
{
public static T Clone<T>(this T entity) where T : class
{
var clone = Activator.CreateInstance(entity.GetType());
var entityPropValueDictionary = entity.AsPropValueDictionary();
foreach (var prop in clone.GetType().GetProperties())
{
clone.GetType().GetProperty(prop.Name).SetValue(clone, entityPropValueDictionary[prop.Name]);
}
return clone as T;
}
public static IDictionary<string, object> AsPropValueDictionary<T>(this T instance, params BindingFlags[] bindingFlags)
{
var runtimeBindingFlags = BindingFlags.Default;
switch (bindingFlags.Count())
{
case 0:
runtimeBindingFlags = BindingFlags.Default;
break;
case 1:
runtimeBindingFlags = bindingFlags[0];
break;
default:
runtimeBindingFlags = bindingFlags.Aggregate(runtimeBindingFlags, (current, bindingFlag) => current | bindingFlag);
break;
}
return runtimeBindingFlags == BindingFlags.Default
? instance.GetType().GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(instance))
: instance.GetType().GetProperties(runtimeBindingFlags).ToDictionary(prop => prop.Name, prop => prop.GetValue(instance));
}
}
}
Result:
I wrote these quick-and-dirty extension methods in a hurry so there are probably some issues with it and they are probably horribly inefficient, but they seemed to work for my use case. They may help you, too.
When I try to deserialized my FooContainer (List) throws me an error. Please, just watch the last part of this code.
public interface IFoo
{
object Value { get; }
}
public abstract class Foo<T> : IFoo
{
[XmlElement("Value")]
public T Value { get; set; }
[XmlIgnore]
object IFoo.Value { get { return Value; } }
}
public class FooA : Foo<string> { }
public class FooB : Foo<int> { }
public class FooC : Foo<List<Double>> { }
[XmlRoot("Foos")]
public class FooContainer : List<IFoo>, IXmlSerializable
{
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
XmlSerializer serial = new XmlSerializer(typeof(FooContainer));
serial.Deserialize(reader);
}
public void WriteXml(XmlWriter writer)
{
ForEach(x =>
{
XmlSerializer serial = new XmlSerializer(x.GetType(),
new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
serial.Serialize(writer, x);
});
}
}
class Program
{
static void Main(string[] args)
{
FooContainer fooList = new FooContainer()
{
new FooA() { Value = "String" },
new FooB() { Value = 2 },
new FooC() { Value = new List<double>() {2, 3.4 } }
};
XmlSerializer serializer = new XmlSerializer(fooList.GetType(),
new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
System.IO.TextWriter textWriter = new System.IO.StreamWriter(#"C:\temp\movie.xml");
serializer.Serialize(textWriter, fooList);
textWriter.Close();
XmlReader reader = XmlReader.Create(#"C:\temp\movie.xml");
var a = serializer.Deserialize(reader);
}
}
What am I doing wrong?
I had the exact same Problem:
To me it seems that you are missing set in your interface IFoo or class Foo. Without set the object becomes readonly and you will receive a StackOverflowException when trying to deserialize XML to Object.
I simply added set to my attributes, and the thing solved itself.
You don't seem to understand what IXmlSerializable is for. It's meant for overriding the default behaviour of an XmlSerializer. If you just spin up another XmlSerializer to actually serialize/deserialize in your WriteXml/ReadXml methods then yes, you will get a StackOverflowException because that serializer is going to call the exact same WriteXml/ReadXml/ method it came from on exactly the same object.
Just get rid of that IXmlSerializable implementation, since it doesn't actually do anything. Or read this CP article:
How to Implement IXmlSerializable Correctly
Basically, you are supposed to use the standard Read* and Write* methods on XmlReader or XmlWriter to read or write the object.
It's not necessarily always wrong to use an XmlSerializer inside a ReadXml or WriteXml method - as long as you're using it to serialize/deserialize a different object, one which neither equals nor contains an instance of the declaring type in the object graph.
I'd debug it to make sure, but my guess is your implementation of ReadXml is recursive. ReadXml calls Deserialize, which calls ReadXml, which calls Deserialize, etc.
ReadXml should read the xml using the reader that's passed in and hydrate the object (i.e. this) based on the Xml data.
from MSDN
The ReadXml method must reconstitute your object using the information
that was written by the WriteXml method.
When this method is called, the reader is positioned at the start of
the element that wraps the information for your type. That is, just
before the start tag that indicates the beginning of a serialized
object. When this method returns, it must have read the entire element
from beginning to end, including all of its contents. Unlike the
WriteXml method, the framework does not handle the wrapper element
automatically. Your implementation must do so. Failing to observe
these positioning rules may cause code to generate unexpected runtime
exceptions or corrupt data.
When implementing this method, you should consider the possibility
that a malicious user might provide a well-formed but invalid XML
representation in order to disable or otherwise alter the behavior of
your application.
I have a class with a couple of members I want to serialise to store state.
However, I want to serialise from WITHIN the class itself, not via some external class feeding it to a formatter.
So in theory I want to do something like:
[DataContract]
class MyClass
{
[DataMember]
private MyCompoundClass _someCompoundField;
[DataMember]
private int _someOtherField;
private void SaveState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
serialiser.WriteObject(stream, this);
}
}
private void LoadState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
this = (MyClass)serialiser.ReadObject(stream);
}
}
}
Now obviously the line
this = (MyClass)serialiser.ReadObject(stream);
is nonsense, but you can see what I'm trying to do. I want to serialise the two fields of my class from within the class. (I am using the WCF serializer, but I assume this will be the same if I use XmlSerializer).
I tried to implement this properly by serialising each field myself like so:
private void SaveState()
{
using (Stream stream = GetStream())
{
//serialise field 1
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyCompoundClass));
serialiser.WriteObject(stream, _someCompoundField);
//serialise field 2
serialiser = new DataContractSerializer(typeof(int));
serialiser.WriteObject(stream, _someOtherField);
}
}
Now this works as a save, but when I come to read the document back in it throws an exception since there are two root nodes in the XML file.
How do I create my "wrapper" node to wrap my fields. Or is there some other way I should be doing this?
Many thanks,
I haven't seen any built-in deserialisation methods which modify an existing object, rather than returning a new one. Your options as I see them are:
Deserialise a new MyClass and copy the members over
Make LoadState static and have it return the deserialised MyClass
Use a different serialisation mechanism which can do what you want
you could at your LoadState do:
private void LoadState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
MyClass deserialized = (MyClass)serialiser.ReadObject(stream);
this._someCompoundField = deserialized._someCompoundField;
this._someOtherField = deserialized._someOtherField;
}
}
Are you tied to a specific serializer? protobuf-net supports that use-case, for example:
[DataContract]
class MyClass
{
[DataMember(Order = 1)]
private MyCompoundClass _someCompoundField;
[DataMember(Order = 2)]
private int _someOtherField;
private void SaveState()
{
using (Stream stream = GetStream())
{
ProtoBuf.Serializer.Serialize(stream, this);
}
}
private void LoadState()
{
using (Stream stream = GetStream())
{
ProtoBuf.Serializer.Merge(stream, this);
}
}
}
Note the addition of Order = n on the member-attributes; that is because protobuf uses numeric identifiers on fields/properties, and needs a way to choose them. You can also use the project-specific [ProtoContract]/[ProtoMember(n)] attributes, but it works with the WCF ones too (as shown).
(Merge is also available on the non-generic 2.0 API - but you pass this in as an argument to Deseroalize instead)
Put your deserialization method in a static method:
class MyClass
{
public static MyClass LoadState()
{
// Deserialize, and return the new MyClass instance.
}
}
To serialize just some objects, annotate some fields to avoid serialization, or create a superclass or interface with just the fields in it you want to serialize.