Serializing a HashSet in a Dictionary - c#

I have a similar Problem to Serializing a HashSet
I have a Class with a Member of type Dictionary<String,HashSet<T>>
When i serialize the Object with BinaryFormatter, and then deserialize it, it comes up empty.
I don't know how, or where to call the workaround posted here.
Any Hints? thanks in advance.
edit:
i tried to convert the hashset to a list, as one of the comments in the other thread suggested.
the object looks like this:
public class THashSet : HashSet<T> , ISerializable
{
public THashSet(SerializationInfo info, StreamingContext context)
{
var list = (List<T>)info.GetValue("hashset", typeof(List<T>));
foreach (T t in list)
this.Add(t);
}
public override void GetObjectData(SerializationInfo info,StreamingContext context)
{
info.AddValue("hashset", this.ToList<T>());
}
when the object containing the THashSet is deserialized (and the constructor is called), the list is recovered correctly, as i see in the debugger.
but after the serializer is done, the object only contains an empty hashset.

Suppose for your T object you haven't override methods GetHashCode and Equals. You need to do it.
UPD: All depends from your object implementation. And object is not so easy as you say. Your sitation, object:
[Serializable]
public class DataClass
{
public DataClass()
{
}
public DataClass(string name, string description)
{
Name = name;
Description = description;
this.Dictionary = new Dictionary<string, HashSet<DataClass>>();
}
public string Name { get; set; }
public string Description { get; set; }
public Dictionary<string, HashSet<DataClass>> Dictionary { get; set; }
}
And serialization/deserialization code:
DataClass dataClass = new DataClass("name", "descr");
dataClass.Dictionary.Add("key1", new HashSet<DataClass>() { new DataClass("sample11", "descr11"), new DataClass("sample12", "descr12") });
dataClass.Dictionary.Add("key2", new HashSet<DataClass>() { new DataClass("sample21", "descr21"), new DataClass("sample22", "descr22") });
dataClass.Dictionary.Add("key3", new HashSet<DataClass>() { new DataClass("sample31", "descr31"), new DataClass("sample32", "descr32") });
byte[] serialized;
var formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, dataClass);
serialized = stream.ToArray();
}
using (MemoryStream streamDeserial = new MemoryStream())
{
streamDeserial.Write(serialized, 0, serialized.Length);
streamDeserial.Seek(0, SeekOrigin.Begin);
var dictDeserial = formatter.Deserialize(streamDeserial) as DataClass;
}
This code works well.

Related

A constructor that takes object from same type

So I want to create constructor for my class EmployeeNodeClass that takes In EmployeeNodeClass object and copies it using a deepclone funtion:
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
to the new object.
At first i thought that it is as simple as
public EmployeeNodeClass(EmployeeNodeClass EMPND)
{
this = DeepClone(EMPND);
}
but then I got the error that this is readonly.
so how can I do it?
It can be done using NewtonSoft JsonConvert.PopulateObject:
Example:
class Entity
{
public List<int> List { get; set; }
public Entity(List<int> list)
{
List = list;
}
public Entity(Entity original)
{
string originalJson = JsonConvert.SerializeObject(original);
JsonConvert.PopulateObject(originalJson, this);
}
}
And using it:
static void Main(string[] args)
{
var entity1 = new Entity(new List<int> { 1, 2, 3 });
var entity2 = new Entity(entity1);
entity1.List[0] = 5;
Console.WriteLine(entity2.List[0]);
}
Note: since this uses NewtonSoft Json, it will only clone public, writable properties. So internal state in private fields (that are not associated with such properties) will be lost.

How to deal with Hashtable property of entity in database using EntityFramework

I have old project which used ADO.NET to access the persistent store. Currently, I want to migrate it to EF (6.1.3, if it matters), in order to support several DB providers with minimal code duplicate.
There is an entity, which contains Hashtable property:
public class Record
{
...
public Hashtable data { get; set; }
}
With ADO.NET, the BinaryFormatter was used to convert this data property to the BLOB, and vice versa:
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, data);
result = stream.GetBuffer();
}
//----------
using (MemoryStream serializationStream = new MemoryStream((byte[])value))
{
BinaryFormatter formatter = new BinaryFormatter();
result = (Hashtable)formatter.Deserialize(serializationStream);
}
Now I need to tell EF how it should store and retrieve that property.
What have I tried
I could store one more property in the entity:
public class Record
{
public byte[] dataRaw { get; set; }
[NotMapped]
public Hashtable data {
get {/*deserialize dataRaw */ }
set { /*Serialize to dataRaw*/}
}
}
But this solution is prone to errors, and special workflow with that property must be followed.
P.S. Actually this question is not about the Hashtable only, but about every custom class which must be stored and retrived in a special way.
Here is a complete solution based on the answer I mentioned above.
I have tested it in linqpad, and it works rather well.
You don't need a special workflow, as the property accessors take care of saving and loading the hash table when needed.
Main Method
void Main()
{
using (var ctx = new TestContext())
{
var hash = new Hashtable();
hash.Add("A", "A");
ctx.Settings.Add(new Settings { Hash = hash });
ctx.SaveChanges();
// load them up...
ctx.Settings.ToArray().Select(_ => _.Hash).Dump();
}
}
Settings Class
public class Settings
{
// a primary key is necessary.
public int Id { get; set; }
[NotMapped]
public Hashtable Hash
{
get;
set;
}
// the backing field can be protected, this helps 'hide' it.
protected virtual byte[] _Hash
{
get
{
return Hash.ToBinary();
}
set
{
Hash = value.FromBinary<Hashtable>();
}
}
}
Extensions to Convert the Values
public static class Extensions
{
public static BinaryPropertyConfiguration BinaryProperty<T>(
this EntityTypeConfiguration<T> mapper,
String propertyName) where T : class
{
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
PropertyInfo pi = type.GetProperty(propertyName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
expr = Expression.Property(expr, pi);
LambdaExpression lambda = Expression.Lambda(expr, arg);
Expression<Func<T, byte[]>> expression = (Expression<Func<T, byte[]>>)lambda;
return mapper.Property(expression);
}
public static byte[] ToBinary<T>(this T instance)
{
if (instance == null)
return null;
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, instance);
return stream.ToArray();
}
}
public static T FromBinary<T>(this byte[] buffer)
{
if (buffer == null)
return default(T);
using (var stream = new MemoryStream(buffer, false))
{
var formatter = new BinaryFormatter();
var instance = formatter.Deserialize(stream);
return (T)instance;
}
}
}
Data Context
public class TestContext : DbContext
{
public DbSet<Settings> Settings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder
.Entity<Settings>()
.BinaryProperty("_Hash")
.HasColumnName("Hashtable");
}
}

XmlNodeConverter only supports deserializing XmlDocuments error when using Json DeserializeObject

I've the following class;
public class MyClass
{
[XmlIgnore]
public string Name { get; set; }
[XmlElement("Name")]
public XmlCDataSection sName
{
get { return new XmlDocument().CreateCDataSection(Name); }
set { Name = value.Value; }
}
}
I've the following function to take a List<> and copy it's contents;
private static T CloneList<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
But in my code when I try;
List<MyClass> oMyClassList = new List<MyClass>();
MyClass oMyClass = new MyClass();
oMyClass.Name = "Hello World's";
oMyClassList.Add(oMyClass);
List<MyClass> oMyClonedClassList = new List<MyClass>(CloneList(oMyClassList));
At the point of executing the following
List<MyClass> oMyClonedClassList = new List<MyClass>(CloneList(oMyClassList));
I get the error XmlNodeConverter only supports deserializing XmlDocuments. The problem occurs because I've added XmlCDataSection into the class.
How can I get around this problem ?
I managed to overcome this problem by changing my CloneList code to the following
public static T DeepClone<T>(T obj)
{
T objResult;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = (T)bf.Deserialize(ms);
}
return objResult;
}
As provided by [Ajith][1] here How do I clone a generic list in C#?
[1]: https://stackoverflow.com/users/853645/ajith "ajith".
Also, to each of the classes that need to be cloned, I had to add [Serializable] at the top of each class as I was getting the exception 'Not marked as serializable'

How can I convert from an IList<x> to a JSON string and back?

I have the following class:
public class TestQuestionHeader
{
public int Id { get; set; }
public int QId { get; set; }
}
and JSON methods:
public static string ToJSONString(this object obj)
{
using (var stream = new MemoryStream())
{
var ser = new DataContractJsonSerializer(obj.GetType());
ser.WriteObject(stream, obj);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
public static T FromJSONString<T>(this string obj)
{
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(obj)))
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
T ret = (T)ser.ReadObject(stream);
return ret;
}
}
I am using these as follows:
IList<TestQuestionHeaders> testQuestionHeaders = xxx;
string test.Questions = JSON.ToJSONString(testQuestionHeaders);
var a = JSON.FromJSONString<TestQuestionHeader>(test.Questions);
Can someone help me to explain why the variable a contains TestQuestionHeader
instead of IList<TestQuestionHeader>
Your FromJSONString method returns an instance of type T. Your call in your example passes TestQuestionHeader as T. You just need to supply the correct type for T.
You'll need to change that line to:
var a = JSON.FromJSONString<List<TestQuestionHeader>>(test.Questions);
That's because your passing TestQuestionHeader as generic type parameter. Try following:
IList<TestQuestionHeader> a = JSON.FromJSONString<List<TestQuestionHeader>>(test.Questions);
Use JSON.NET, the best JSON library for .NET.
See: http://james.newtonking.com/json/help/index.html

C# - How to use a interface for a generic list when serializing

I have a generic list say and I want to serialize it.
I want to use a interface for the generic list which can't be serialized
so you have to use the instance. Like this
MyClass implements IMyClass.
List<IMyClass> list = DeserializeMyClass(path); //Can't do this right
So have to do this
List<MyClass> list = DeserializeMyClass(path);
So question is can i now cast to
List<IMyClass> ilist = (IMyClass)list;
Malcolm
This will work, but I'm not sure it's the best way:
List<Test> list = new List<Test>();
List<ITest> ilist = list.ConvertAll<ITest>(x => (ITest)x);
You appear to be running in to the fact that C# 3.0 lacks co- and contra-variance.
You probably want to use:
list.Cast<IMayClass>().ToList();
you can serialize and deserialize interfaces with the BinaryFormatter, but this is not Xml serialization...
What you described is exactly what I need. in addition all my concrete classes are generic..
I have :
IMyInterface interface
MyConcreteClass1 class
MyConcreteClass2 class
and I also have to serialize a collection of such objects (List), with Xml serialization...
looks like it is impossible!
I realize this is an old question but for those that are looking for an answer here is how you can do this is .NET v4
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApplication6
{
internal class Program
{
private static void Main(string[] args)
{
List<ImyInterface> list = new List<ImyInterface>();
list.Add(new MyClass {MyData = "Test1", SpecialData = "special"});
list.Add(new MyOtherClass {MyData = "Test2", OtherData = "other"});
Serialize("c:\\test.dat", list);
List<ImyInterface> theList = Deserialize<List<ImyInterface>>("c:\\test.dat");
}
public static void Serialize<T>(string filename, T objectToSerialize)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
public static T Deserialize<T>(string filename)
{
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
T objectToSerialize = (T) bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
}
public interface ImyInterface
{
string MyData { get; set; }
}
[Serializable]
public class MyClass : ImyInterface
{
public string MyData { get; set; }
public string SpecialData { get; set; }
}
[Serializable]
public class MyOtherClass : ImyInterface
{
public string MyData { get; set; }
public string OtherData { get; set; }
}
}
Ok this is what it should have been:
Listl<IMyclass> list = DeserializeMyClass(path); //Can't do this right
So have to do this:
List<MyClass> list = DeserializeMyClass(path);
So question is can i now cast to:
List<IMyclass> ilist = (IMyClass)list;

Categories

Resources