Serializing and deserializing a List<List<object>> with BinaryFormatter - c#

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.

Related

Serialize a non-serializable custom object from a nuget package and store it in SQLite database

I'm working with some highly custom objects from a nuget package that I need to store in the local SQLite db using Xamarin. I tried using this code
public static byte[] Serialize(ComplexType c)
{
byte[] arrayData;
using(MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize( stream, c );
arrayData = stream.ToArray();
stream.Close();
}
return arrayData;
}
public static ComplexType Deserialize(byte[] arrayData)
{
ComplexType c;
using(MemoryStream stream = new MemoryStream())
{
stream.Write( arrayData, 0, arrayData.Length );
stream.Seek( 0, SeekOrigin.Begin );
BinaryFormatter formatter = new BinaryFormatter();
c = (ComplexType) formatter.Deserialize( stream );
}
return c;
}
to serialize and store the object then retrieve it and deserialize it. It seems like it worked fine to do the serialization but now it turns out that the object is not marked serializable. I can't add the SerializableAttribute property to it because it's from a nuget. I tried editing the object definition in the nuget but of course it's locked.
Is there any easy way to pull off serializing an object not marked serializable or perhaps some other simple method of storing a non-serializable custom object in a SQLite database? Or should I just byte the bullet and write really complicated setters and getters to store all of the custom object's individual custom properties broken down into their individual lists of standard properties and basically deconstruct and reconstruct the object every time it goes to and from the database?
I'm seeing mixed reports on ISerializable and derived classes. Will implementing ISerializable on a derived class from the custom object allow the derived class to be serialized? What about IXMLSerializable? Will either of these work? I just want to get some clarification if possible before I go way down the wrong rabbit hole.

C# binary serialization and deserialization of generic lists

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!

Are Hashtables Serializable?

I see a pervasive belief (2009 article) throughout the internet that the Hashtable class is not serializable; however, I cannot find any modern documentation that supports this notion.
The belief stems from another ill-documented belief that the IDictionary interface prevents serialization; however, I cannot find anything in MSDN that supports this claim, today.
Further, Hashtable implements ISerializable and contains extension methods that accept serialization information.
So, what's the deal? Is Hashtable serializable? Where is the documentation that supports this notion surrounding IDictionary?
Further Clarification (please read):
The statement that IDictionary is not serializable is supported by plenty of documentation; however, this focuses on the use of XML-based serialization interactions with a class. ISerializable as mentioned both in the comments, below, and through MSDN indicates that a class is serializable. It also means the class the must be responsible for its own serialization.
I think this negates the statement that a Hashtable is not serializable. That is perhaps the genesis of my question.
The pervasive belief is so pervasive because it's true:
var t = new Hashtable();
t.Add("Hi!", "I'm here");
t.Add("Hm", "Yup");
var serializer = new XmlSerializer(typeof(Hashtable));
using (var sw = new StringWriter())
{
serializer.Serialize(sw, t);
Console.WriteLine(sw.ToString());
}
throws
NotSupportedException: The type System.Collections.Hashtable is not supported because it implements IDictionary.
That doesn't mean that it's literally impossible to serialize a hash table. Of course I can just iterate over all the keys and values, write them to a string and then reconstruct the hashtable from that. It's just that I can't use the serialization infrastructure fully.
What's the reasoning here? It's actually quite simple - XmlSerializer is designed to produce good XML, in the spirit of the interchange format XML was designed to be. And XML doesn't have any kind of dictionary or "key-value" mechanism that would fit. So to support hashtable serialization, they'd have to make their own "sub-format" with its own rules. And back when .NET was being designed, this was a huge no-no - XML was an interchange format. Any extension (hah) to the format means you're no longer compatible, no matter how good of an idea you have.
Of course, nowadays, everyone and their grandmother are producing XML data that isn't used for interchange purposes. And it's not entirely a bad thing (after all, .NET config files are also a XML format). But it's also kind of wrong.
In contrast, take something like BinaryFormatter. That's a class where the .NET team designed the whole format, and isn't limited by a standard. And lo and behold - BinaryFormatter can serialize and deserialize a Hashtable just fine.
So the slightly more correct belief would be "Hashtable cannot be serialized to valid standard XML. The XmlSerializer class in particular will throw an error when you attempt to serialize a Hashtable."
Does Hashtable implement ISerializable? Absolutely:
public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable
Can we serializae a Hashtable to XML? Let's try it:
var hash = new System.Collections.Hashtable();
hash[7] = "7";
hash[8] = "8";
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Hashtable));
TextWriter writer = new System.IO.StreamWriter(#"C:\SomeFile.xml");
serializer.Serialize(writer, hash);
Result... Error as you expected
An exception of type 'System.NotSupportedException' occurred in System.Xml.dll but was not handled in user code
Additional information: The type System.Collections.Hashtable is not supported because it implements IDictionary.
So, it would appear that indeed, it's still the case in .Net 4.5+
But lets try one more time with a binary serialization...
var hash = new System.Collections.Hashtable();
hash[7] = "7";
hash[8] = "8";
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Stream stream = new FileStream(#"C:\SomeFolder\SomeFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, hash);
stream.Close();
Result... No Errors thrown... So the issue appears to be related to IDictionary and XmlSerialization, but not all Serialization
If you really need to do this to XML, ManoDestra had a nice link https://blogs.msdn.microsoft.com/adam/2010/09/10/how-to-serialize-a-dictionary-or-hashtable-in-c/
Also, interestingly, XML Serialization mentions that you can't serialize unsigned longs or collections there-of.
Microsoft XML Serialization (MSDN)
Microsoft seems to say that it is certainly possible to do this.
https://msdn.microsoft.com/en-us/library/b85344hz(v=vs.110).aspx
using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
public class App
{
[STAThread]
static void Main()
{
Serialize();
Deserialize();
}
static void Serialize()
{
// Create a hashtable of values that will eventually be serialized.
Hashtable addresses = new Hashtable();
addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052");
addresses.Add("Fred", "987 Pine Road, Phila., PA 19116");
addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");
// To serialize the hashtable and its key/value pairs,
// you must first open a stream for writing.
// In this case, use a file stream.
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, addresses);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
static void Deserialize()
{
// Declare the hashtable reference.
Hashtable addresses = null;
// Open the file containing the data that you want to deserialize.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the hashtable from the file and
// assign the reference to the local variable.
addresses = (Hashtable) formatter.Deserialize(fs);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
// To prove that the table deserialized correctly,
// display the key/value pairs.
foreach (DictionaryEntry de in addresses)
{
Console.WriteLine("{0} lives at {1}.", de.Key, de.Value);
}
}
}

convert dictionary or list to byte[]

Ok, i've seen many similar questions both on here and unity forums asking about converting from one format to another. I've got a (hopefully) simple question that i just can't find the answer for. I'm using the game-center plugin from Prime31 to handle a turn based multi-player game. Inside the plugin for Prime31 they ask you for a byte[] to send to the other players. (State data) So the question is, what would be a good way to convert a List to a byte array AND then convert them back from byte array?
for reference this is as complicated a class as i need, i might need to add more members later, but not any different types. ALSO the list of int's(cards in hand) could easily be 4 separate int if that makes converting the list of PokerPlayers to an byte[] any easier. Also at this list is not a set length but will always be 4-8.
public class PokerPlayer{
public string playerID;
public string alias;
public int wildCard;
public List<int> cardsInHand;
public int chips;
}
I feel like the when i see the answer I'm going to smack myself for not seeing the answer sooner. Any pointers/ links to relevant materials would be sweet, i've searched google for a good 3 hours now with similar (SO similar) but not quite the same questions.
You may want to try serialization.
var binFormatter = new BinaryFormatter();
var mStream = new MemoryStream();
binFormatter.Serialize(mStream, myObjToSerialize);
//This gives you the byte array.
mStream.ToArray();
And then if you want to turn the byte array back into an object:
var mStream = new MemoryStream();
var binFormatter = new BinaryFormatter();
// Where 'objectBytes' is your byte array.
mStream.Write (objectBytes, 0, objectBytes.Length);
mStream.Position = 0;
var myObject = binFormatter.Deserialize(mStream) as YourObjectType;
Update:
Microsoft warns about using BinaryFormatter because it is "insecure and can't be made secure".
Please read aka.ms/binaryformatter for more details.
Preferred alternatives
.NET offers several in-box serializers that can handle untrusted data safely:
XmlSerializer and DataContractSerializer to serialize object graphs into and from XML. Do not confuse DataContractSerializer with NetDataContractSerializer.
BinaryReader and BinaryWriter for XML and JSON.
The System.Text.Json APIs to serialize object graphs into JSON.
BinaryFormatter is now a security risk. If I find a good way to do this without using it I'll be back
https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/binaryformatter-serialization-obsolete
Edit:
This is still the top result in Google so I'll show what I've done to move away from BinaryFormatter
You need Newtonsoft.Json
public static class ExtendedSerializerExtensions
{
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
};
public static byte[] Serialize<T>(this T source)
{
var asString = JsonConvert.SerializeObject(source, SerializerSettings);
return Encoding.Unicode.GetBytes(asString);
}
public static T Deserialize<T>(this byte[] source)
{
var asString = Encoding.Unicode.GetString(source);
return JsonConvert.DeserializeObject<T>(asString);
}
}
It's not very far to go from here if you need a stream rather than a byte array
Converting data into byte stream (and back) is called serialization (and deserialization).
You can use the BinaryFormatter class to do so.

c# binary serialization to file line by line or how to seperate

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());

Categories