I've been getting an error during deserialization:
SerializationException: Could not find type 'System.Collections.Generic.List`1[[ExampleNamespace.ExampleClass, Assembly-CSharp, Version=0.1.6279.22118, Culture=neutral, PublicKeyToken=null]]'.
First I have serialized a custom [Serializable] class (saveStructure):
BinaryFormatter formatter = new BinaryFormatter();
FileStream file = File.Open(saveFilePath, FileMode.Open);
formatter.Serialize(file, saveStructure);
file.Close();
Which contains a few fields along with a List<ExampleClass> field.
MyCustomClass is also a [Serializable] class.
It seems to serialize the structure properly, but can not read it back during deserialization:
BinaryFormatter formatter = new BinaryFormatter();
FileStream file = File.Open(saveFilePath, FileMode.Open);
SaveStructure saveStructure = (SaveStructure)formatter.Deserialize(file);
file.Close();
I am aware of XmlSerializer, however I do not want to expose the data to the users.
Thanks in advance!
Edit:
I have solved my problem by using Arrays instead of Lists, however, if someone is to offer a solution for the List problem, I'd still be grateful!
Related
I'm trying to serialize a FormCollection object, and based on what I have researched, it inherits NameObjectCollectionBase so it also inherits GetObjectData and ISerializable. Wouldn't this mean it is serializable?
https://msdn.microsoft.com/en-us/library/system.web.mvc.formcollection(v=vs.118).aspx
Here's a snippet of what I'm trying:
BinaryFormatter formatter = new BinaryFormatter();
//Serialize
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, data);
string test = Convert.ToBase64String(stream.ToArray());
Session["test"] = test;
};
//Deserialize
using (MemoryStream stream = new MemoryStream(Convert.FromBase64String((string)Session["test"])))
{
data = (FormCollection) formatter.Deserialize(stream);
}
I, unfortunately, got this error:
System.Runtime.Serialization.SerializationException: Type 'System.Web.Mvc.FormCollection' in Assembly 'System.Web.Mvc, Version=5.2.3.0, Culture=neutral... is not marked as serializable.
Because this is a sealed class, I cannot extend it and add the [Serializable] Attribute.
My questions is:
Why I can't serialize FormCollection like this?
And how I can serialize/deserialize a FormCollection object?
It cannot be serialized like this because it lacks [Serializable] attribute. That means developers of this class had no intention to make it serializable (with BinaryFormatter). The fact it's parent class implements ISerializable and marked with [Serializable] does not change anything - child class might have it's own internal details which will be lost during serialization if it was allowed to serialize any descendant of serializable class.
If you want to use BinaryFormatter (which might or might not be the best way) - you can do it like this:
BinaryFormatter formatter = new BinaryFormatter();
//Serialize
string serialized;
using (MemoryStream stream = new MemoryStream())
{
// pass FormCollection to constructor of new NameValueCollection
// that way we kind of convert it to NameValueCollection which is serializable
// of course we lost any FormCollection-specific details (if there were any)
formatter.Serialize(stream, new NameValueCollection(data));
serialized = Convert.ToBase64String(stream.ToArray());
};
//Deserialize
using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(serialized))) {
// deserialize as NameValueCollection then create new
// FormCollection from that
data = new FormCollection((NameValueCollection) formatter.Deserialize(stream));
}
Let's say I have
List<object> mainList = new List<object>();
And it contains
List<string> stringList = new List<string();
List<CustomClass> custList = new List<CustomClass>();
mainList.Add(stringList);
mainList.Add(custList);
To serialize
Stream stream;
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, mainList);
To deserialize
Stream stream = (Stream)o;
BinaryFormatter formatter = new BinaryFormatter();
List<object> retrievedList = (List<object>)formatter.Deserialize(stream);
At this point, I receive an error that the stream read (deserialization) reached the end of the stream without retrieving a value.
Do I need to specify something besides...
[Serializable]
public class CustomClass { .... }
in the custom class to make this work? Can I not deserialize a List> that contains different type of object every time?
I tried
IList list = (IList)Activator.CreateInstance(typeof(custClassList[0]))
and tried to send and receive this, but got the same issue.
I can however serialize and deserialize a specified type or List, but I really need it to be dynamic.
Basically, BinaryFormatter is a joke. It works in some cases, but will fail in almost identical scenarios for unknown reasons.
The best and superior alternative to BinaryFormatter is the third-party library protobuf-net (https://github.com/mgravell/protobuf-net), developed by Marc Gravel.
This beauty solved all the problems I was having in one pass. It's much easier to set up and reacts more perfectly to complex, custom classes.
I should also mention that it's faster, in the terms of de/serialization.
In order to fix the issue that causes the error "stream read (deserialization) reached the end of the stream ", the stream position needs to reset to 0 as follows...
stream.Position = 0;
Do I need to specify something besides...
[Serializable] public class CustomClass { .... }
Nope...That should be good for what you are doing.
in the custom class to make this work? Can I not deserialize a List>
that contains different type of object every time?
You should be able to serialize any object.
I have a list of events and I save it in a binary file using this code
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
{
using (BinaryWriter w = new BinaryWriter(fs))
{
foreach (MacroEvent macroEvent in events)
{
w.Write(macroEvent.TimeSinceLastEvent);
}
}
}
but I'm confused to how I read and get it back again in a list?
The following recipe is a good guide on how to implement ISerializable for an object you want to serialize and deserialize with a BinaryFormatter:
http://www.switchonthecode.com/tutorials/csharp-tutorial-serialize-objects-to-a-file
Here is the NET 4.0 documentation on BinaryFormatter:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx
and ISerializable:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx
Sequential file access File using serialization
Add
Using system.Io
Using system.Runtime.Serialzation.Formatters.Binary
Using System.Runtime.Serialization
Using Macro Events
name space created fileform : macroform
//Object For serializing RecordSerializables in binary format
Private Binary formatter = new binaryFormatter();
Private file stream output; //stream for writing to a file
Use method Deserialize to read data
Cast result of Deserialize to type serializeable to type serializeable this cast is necessary ,because Deserialize returns a refrence of type object and need to access properties that belong to class serializable. If an error during deserialization is thrown
a serialization is thrown and the file stream is closed
Private BinaryFormatter eader = new BinaryFormatter();
Private File stream input; // stream for reading from file
How do I deserialize a binary file to a string?
This is my sample code so far:
public function serialize()
{
FileStream fs = new FileStream("test.txt", FileMode.Append);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, textBox1.Text);
fs.Flush();
fs.Close();
}
public function deserialize()
{
FileStream fs = File.Open(openFileDialog1.FileName, FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();
richTextBox1.Text = formatter.Deserialize(mystream) as string;
fs.Flush();
fs.Close();
}
When I start to debug the application, it only shows the first string of the stream. The rest of the stream did not show up. How should I fix this?
Just use
System.IO.File.WriteAllText(fileName, textBox1.Text);
and
textBox1.Text = System.IO.File.ReadAllText(fileName);
The right way to do this is to put all of the values that you want to serialize into a serializable structure and then serialize that structure. On the other end you deserialize that structure and then put the values where they need to go.
Note that the binary serializer produces binary, not text output. If you want human readable serialized data you can use the XmlSerializer instead.
Binary serialization serializes object graphs; it doesn't just write strings.
It wouldn't make sense to combine object graphs.
You should read and write the file directly using the File class.
I have a collection of objects at runtime, which is already serializable, I need to persist the state of the object to a file. I did a quick coding using BinaryFormatter and saved A serialized object to a file.
I was thinking that I can save object per line. but when i open the file in a notepad, it was longer than a line. It wasnt scrolling. How can i store an binary serialized object per line?
I am aware that i can use a separator after each object so while reading them back to the application, i can know the end of the object. Well, according to information theory, this increases the size of the data(Sipser book).
What s the best algorithm to come up with a separator that woudldnt break the information?
Instead of binary serialization? Do you think JSon format is more feasible? can i store the entity in a json format, line by line?
Also, serialization/deserialization introduces overhead, hits the performance. Would Json be faster?
ideas?
Thanks.
Thanks.
Serialization functions like a FIFO queue, you dont have to read parts of the file because the formatter does it for you you just have to know the order you pushed objects inside.
public class Test
{
public void testSerialize()
{
TestObj obj = new TestObj();
obj.str = "Some String";
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, obj);
formatter.Serialize(stream, 1);
formatter.Serialize(stream, DateTime.Now);
stream.Close();
}
public void TestDeserialize()
{
Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.None);
IFormatter formatter = new BinaryFormatter();
TestObj obj = (TestObj)formatter.Deserialize(stream);
int obj2 = (int)formatter.Deserialize(stream);
DateTime dt = (DateTime)formatter.Deserialize(stream);
stream.Close();
}
}
[Serializable]
class TestObj
{
public string str = "1";
int i = 2;
}
Well,
Serialization/deserialization introduces overhead, would Json be faster?
JSON is still a form of serialisation, and no it probably wouldn't be faster than binary serialisation - binary serialisation is intended to be compact and quick, wheras JSON serialisation puts more emphasis on readability and so many be slower as is very likely to be less compact.
You could serialise each object individually and emit some separator between each object (e.g. a newline character), but I don't know what separator you could use that is guarenteed to not appear in the serialised data (what happens if you serialise a string containing a newline character?).
If you use a separator that the .Net serialisation framework emits then obviously you will make it difficult (if not impossible) to correctly determine where the breaks between objects are leading to deserialisation failures.
Why exactly do you want to put each object on its own line?
Binary serialization saves the data to arbitrary bytes; these bytes can include newline characters.
You're asking to use newlines as separators. Newlines are no different from other separators; they will also increase the size of the data.
You could also create a ArrayList and add the objects to it and then serialize it ;)
ArrayList list = new ArrayList();
list.Add(1);
list.Add("Hello World");
list.Add(DateTime.Now);
BinaryFormatter bf = new BinaryFormatter();
FileStream fsout = new FileStream("file.dat", FileMode.Create);
bf.Serialize(fsout, list);
fsout.Close();
FileStream fsin = new FileStream("file.dat", FileMode.Open);
ArrayList list2 = (ArrayList)bf.Deserialize(fsin);
fsin.Close();
foreach (object o in list2)
Console.WriteLine(o.GetType());