How can I create deserialization method that can take an object of class or any of derived classes?
public class Config
{
public string appname;
}
public class CustomConfig1 : Config
{
public string CustomConfig1Param1;
public string CustomConfig1Param2;
}
public class CustomConfig2 : Config
{
public string CustomConfig2Param1;
public string CustomConfig2Param2;
}
I want to get something like serialization method that defines type of input object:
public string serialize(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
StringWriter serialized = new StringWriter();
serializer.Serialize(serialized, obj);
return serialized.ToString();
}
But when I read an XML from DB I can't define the type of object, so I can't pass it to XmlSerializer. It may be the Config object or any of derived classes
Please help. How can I define the type of input object?
[XmlInclude(typeof(CustomConfig1))]
[XmlInclude(typeof(CustomConfig2))]
public class Config
{
public string appname;
}
Then just serialize/deserialize specifying typeof(Config); the library will give you back an instance of the appropriate type based on the data.
Edit: full example, including the preference to not hard-code the sub-types:
using System;
using System.IO;
using System.Xml.Serialization;
public class Config
{
public string appname;
}
public class CustomConfig1 : Config
{
public string CustomConfig1Param1;
public string CustomConfig1Param2;
}
public class CustomConfig2 : Config
{
public string CustomConfig2Param1;
public string CustomConfig2Param2;
}
static class Program
{
static void Main()
{
var original = new CustomConfig1
{
appname = "foo",
CustomConfig1Param1 = "x",
CustomConfig1Param2 = "y"
};
var xml = Serialize(original);
var clone = DeserializeConfig(xml);
Console.WriteLine(clone.appname);
var typed = (CustomConfig1)clone;
Console.WriteLine(typed.CustomConfig1Param1);
Console.WriteLine(typed.CustomConfig1Param2);
}
public static string Serialize(Config obj)
{
using (var serialized = new StringWriter())
{
GetConfigSerializer().Serialize(serialized, obj);
return serialized.ToString();
}
}
public static Config DeserializeConfig(string xml)
{
using(var reader = new StringReader(xml))
{
return (Config)GetConfigSerializer().Deserialize(reader);
}
}
static Type[] GetKnownTypes()
{
// TODO: resolve types properly
return new[] { typeof(CustomConfig1), typeof(CustomConfig2) };
}
private static XmlSerializer configSerializer;
public static XmlSerializer GetConfigSerializer()
{
return configSerializer ?? (configSerializer =
new XmlSerializer(typeof(Config), GetKnownTypes()));
}
}
Related
this might have a easy/quick solution, but from my investigation I didn't manage to find it.
public interface IBaseMessage
{
}
public interface IRefreshMessage : IBaseMessage
{
}
Both are implemented by concrete classes in a Library.Message
They are stored inside a List<IBaseMessage> and when I serialize the object to be send over the network (one by one) it is marked as IBaseMessage even tough some are IRefrehMessage
Issue: on deserialization (on another PC) they are reconstructed as IBaseMessage and all the information from IRefreshMessage is lost.
Assumption: I believe there must be some JSON class attribute that allows me to specify into what to be serialized?
Thank you, and sorry for a rather silly question
Edit:
Using this class to serialize/deserialize:
using Newtonsoft.Json.Linq;
public class JMessage
{
public Type Type { get; set; }
public JToken Value { get; set; }
public static JMessage FromValue<T>(T value)
{
return new JMessage { Type = typeof(T), Value = JToken.FromObject(value) };
}
public static string Serialize(JMessage message)
{
return JToken.FromObject(message).ToString();
}
public static JMessage Deserialize(string data)
{
return JToken.Parse(data).ToObject<JMessage>();
}
Once is calls
string data = JMessage.Serialize(JMessage.FromValue(message));
I get:
{
"Type": "Universal_Tool_Manager.Messages.Message.Interfaces.IBaseMessage, Universal Tool Manager.Messages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Value": {
"Propagation": 2,
"State": 0
}
}
Hope this helps.
JSON.NET allows you to specify how to handle serialization and deserialization using JsonSerializerSettings:
class Program
{
static void Main(string[] args)
{
var items = new List<Test>
{
new Test() {Hello = "Hi"},
new TestDerived() {Hello = "hello", Second = "World"}
};
var settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects
};
var text = JsonConvert.SerializeObject(items, settings);
var data = JsonConvert.DeserializeObject<IEnumerable<Test>>(text, settings);
}
}
public class Test
{
public string Hello { get; set; }
}
public class TestDerived : Test
{
public string Second { get; set; }
}
In this sample the generated JSON will contain a name of the actual type which was serialized and JSON.NET will use this information to deserialize back to the correct derived type - data[1] is TestDerived in my example code.
To use JsonSerializerSettings with FromObject and Parse methods, you will need to create an instance of JsonSerializer:
var serializer = sonSerializer.Create(settings);
JToken.FromObject(o, serializer)
//and
JToken.Parse(data).ToObject<JMessage>(serializer);
I've asked the wrong question here :)
public static JMessage FromValue<T>(T value)
{
return new JMessage { Type = **typeof(T)**, Value = JToken.FromObject(value) };
}
The issue was on typeof(T) which of course it will always return the base interface IBaseInterface since i'm using a
List<IBaseInterface>,
The solution was to use value.GetType(),
sorry for the rookie mistake
I have an object I would like to serialize into json in Unity to send to a service via REST call. In .NET I know you can easily ignore null properties.
[JsonProperty("some_model", NullValueHandling = NullValueHandling.Ignore)]
public class SomeModel
{
....
}
Is this possible using FullSerializer in Unity?
Currently I have
fsData data = null;
fsResult r = sm_Serializer.TrySerialize(objectToSerialize, out data);
string sendjson = data.ToString();
Is there a similar attribute I can add to the DataModel using FullSerializer?
[fsObject(ignoreNullProperties)]
public class SomeModel
{
....
}
Looks like one answer is custom converters.
private static fsSerializer sm_Serializer = new fsSerializer();
[fsObject(Converter = typeof(CustomConverter))]
public class SomeClass
{
string MyProp { get; set; }
}
public class CustomConverter : fsConverter
{
private static fsSerializer sm_Serializer = new fsSerializer();
public override bool CanProcess(Type type)
{
return type == typeof(SomeClass);
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
throw new NotImplementedException();
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
SomeClass someClass = (SomeClass)instance;
serialized = null;
Dictionary<string, fsData> serialization = new Dictionary<string, fsData>();
fsData tempData = null;
if (someClass.MyProp != null)
{
sm_Serializer.TrySerialize(someClass.MyProp, out tempData);
serialization.Add("myProp", tempData);
}
serialized = new fsData(serialization);
return fsResult.Success;
}
}
This works but any other suggestions are greatly appreciated!
I have a class I found on another post that I'm trying to modify.
using System;
using System.IO;
namespace Misc
{
internal class ConfigManager
{
private string _sConfigFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}.xml", AppDomain.CurrentDomain.FriendlyName));
private Config m_oConfig = new Config();
public Config MyConfig
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (Config)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
}
I'd like to pass in an object of type X and have it save. On that same premise, I'd like to pass in a type and have it pass back the object of type X. Right now, it is hard coded to use Config. So, if there is a way to pass in the class object (?) then I'd like it to save it as that object and/or return it of that object.
Is that possible? If so, how would I go about doing this?
Use generic:
internal class ConfigManager<T>
{
private string _fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}.xml", AppDomain.CurrentDomain.FriendlyName));
private T _config;
private XmlSerializer serializer = new XmlSerializer(typeof(T));
public T MyConfig
{
get { return _config; }
set { _config = value; }
}
public void LoadConfig()
{
if (File.Exists(_fileName))
{
using (var reader = File.OpenText(_fileName))
{
_config = (T)serializer.Deserialize(reader);
}
}
}
public void SaveConfig()
{
using (var writer = File.CreateText(_fileName))
{
serializer.Serialize(writer, _config);
}
}
}
Usage:
var man = new ConfigManager<Foo>();
Basically, we'd need to make it work with Generics. So, we start by giving it a type variable, and replace every use of the class Config with T:
internal class Manager<T>
{
private T m_oObj; // etc
Next, I'll just do one method; you can do the rest. (and I'm removed the explicit namespaces, cuz they're ugly)
using System.IO;
using System.Xml.Serialization;
public void LoadConfig<T>()
{
if (File.Exists(_sConfigFileName))
{
var srReader = File.OpenText(_sConfigFileName);
var xsSerializer = new XmlSerializer(typeof(T));
var oData = xsSerializer.Deserialize(srReader);
m_oObj = (T)oData;
srReader.Close();
}
}
{
"Class1": {
"Class2": [
{"Name": "DerivedV1"},
{"Name": "DerivedV2"},
{"Name": "DerivedV3"}
]
}
}
JsonConvert.DeserializeObject<Class1>(jsonString, settings);
public class Class1
{
public List<BaseClass> DerivedClasses { get; set; }
}
public abstract BaseClass
{
public string Name { get; set; }
public abstract bool DoSomething;
}
public class DerivedV1 : BaseClass
{
public override bool DoSomething()
{
// Logic here, different for each derived class.
}
}
When trying to deserialize Class1, I can't figure out how to create the list of derived classed from name. I can't declare something like List BaseClass where BaseClass is abstract and I'm not sure how to use reflection during deserialization within Class2 to determine the derived class from the "name" value. I also looked into ICloneable but didn't get anywhere with it in this context.
Edit:
Here is what I ended up creating and calling from get and set
public static List<T> DeserializeJObjectsToObjects<T>(IEnumerable<JObject> jObjects, string typeKey, string nameSpaceOfClass)
{
Assembly assembly = Assembly.GetExecutingAssembly();
List<T> convert = new List<T>();
foreach (var jObject in jObjects)
{
JToken typeName;
jObject.TryGetValue(typeKey, out typeName);
string fullNameSpace = string.Format(namespaceFormat, nameSpaceOfClass, typeName);
Type t = Type.GetType(string.Format(fullNameSpace));
convert.Add((T) Activator.CreateInstance(t));
}
return convert;
}
public static List<JObject> SerializeObjectsToJObjects<T>(IEnumerable<T> variableObjects )
{
List<JObject> convert = new List<JObject>();
foreach (T variableObject in variableObjects)
{
var jsonString = JsonConvert.SerializeObject(variableObject);
convert.Add(JObject.Parse(jsonString));
}
return convert;
}
First, some notes - I don't use JSonConvert, but there are articles that show you how to do this with. See Json.net serialize/deserialize derived types?, for example. However, you didn't include a json.net tag, so I'm assuming this should hopefully help, or at least point you to the right place.
I used the built in .Net JavaScriptSerializer. You may need to adjust this to work with your input. I created my input based on your code, and my json looks nothing like yours. So, you may still have some work left.
I was able to get it working with a SimpleTypeResolver. Code below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 oClass = new Class1();
DerivedV1 v1 = new DerivedV1();
v1.Name = "DerivedV1";
oClass.DerivedClasses.Add(v1);
DerivedV2 v2 = new DerivedV2();
v2.Name = "DerivedV2";
oClass.DerivedClasses.Add(v2);
DerivedV3 v3 = new DerivedV3();
v3.Name = "DerivedV3";
oClass.DerivedClasses.Add(v3);
JavaScriptSerializer ser = new JavaScriptSerializer(new SimpleTypeResolver());
string sSer = ser.Serialize(oClass);
var test =ser.Deserialize(sSer,typeof(Class1));
foreach (var tst in ((Class1)test).DerivedClasses)
{
Console.WriteLine(tst.Name + Environment.NewLine);
Console.WriteLine(tst.GetType().ToString() + Environment.NewLine);
}
}
public class Class1
{
public List<BaseClass> DerivedClasses { get; set; }
public Class1()
{
DerivedClasses = new List<BaseClass>();
}
}
public abstract class BaseClass
{
public string Name { get; set; }
private bool _dosom;
public abstract bool DoSomething();
public BaseClass(){}
}
public class DerivedV1 : BaseClass
{
public override bool DoSomething()
{
return true;
// Logic here, different for each derived class.
}
}
public class DerivedV2 : BaseClass
{
public override bool DoSomething()
{
return false;
// Logic here, different for each derived class.
}
}
public class DerivedV3 : BaseClass
{
public override bool DoSomething()
{
return true;
// Logic here, different for each derived class.
}
}
}
}
my output json (with the SimpleTypeResolver):
{"__type":"WindowsFormsApplication6.Form1+Class1, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","DerivedClasses":[{"__type":"WindowsFormsApplication6.Form1+DerivedV1, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV1"},{"__type":"WindowsFormsApplication6.Form1+DerivedV2, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV2"},{"__type":"WindowsFormsApplication6.Form1+DerivedV3, WindowsFormsApplication6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"DerivedV3"}]}
and without the type resolver, for comparison (causes errors):
{"DerivedClasses":[{"Name":"DerivedV1"},{"Name":"DerivedV2"},{"Name":"DerivedV3"}]}
And once I deserialize (in the for loop, Console.WriteLine)...
DerivedV1
WindowsFormsApplication6.Form1+DerivedV1
DerivedV2
WindowsFormsApplication6.Form1+DerivedV2
DerivedV3
WindowsFormsApplication6.Form1+DerivedV3
Using this as my solution.
public static List<T> DeserializeJObjectsToObjects<T>(IEnumerable<JObject> jObjects, string typeKey, string nameSpaceOfClass)
{
Assembly assembly = Assembly.GetExecutingAssembly();
List<T> convert = new List<T>();
foreach (var jObject in jObjects)
{
JToken typeName;
jObject.TryGetValue(typeKey, out typeName);
string fullNameSpace = string.Format(nameSpaceFormat, nameSpaceOfClass, typeName);
Type t = Type.GetType(string.Format(fullNameSpace));
convert.Add((T) Activator.CreateInstance(t));
}
return convert;
}
public static List<JObject> SerializeObjectsToJObjects<T>(IEnumerable<T> variableObjects )
{
List<JObject> convert = new List<JObject>();
foreach (T variableObject in variableObjects)
{
var jsonString = JsonConvert.SerializeObject(variableObject);
convert.Add(JObject.Parse(jsonString));
}
return convert;
}
How can I create deserialization method that can take an object of class or any of derived classes?
public class Config
{
public string appname;
}
public class CustomConfig1 : Config
{
public string CustomConfig1Param1;
public string CustomConfig1Param2;
}
public class CustomConfig2 : Config
{
public string CustomConfig2Param1;
public string CustomConfig2Param2;
}
I want to get something like serialization method that defines type of input object:
public string serialize(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
StringWriter serialized = new StringWriter();
serializer.Serialize(serialized, obj);
return serialized.ToString();
}
But when I read an XML from DB I can't define the type of object, so I can't pass it to XmlSerializer. It may be the Config object or any of derived classes
Please help. How can I define the type of input object?
[XmlInclude(typeof(CustomConfig1))]
[XmlInclude(typeof(CustomConfig2))]
public class Config
{
public string appname;
}
Then just serialize/deserialize specifying typeof(Config); the library will give you back an instance of the appropriate type based on the data.
Edit: full example, including the preference to not hard-code the sub-types:
using System;
using System.IO;
using System.Xml.Serialization;
public class Config
{
public string appname;
}
public class CustomConfig1 : Config
{
public string CustomConfig1Param1;
public string CustomConfig1Param2;
}
public class CustomConfig2 : Config
{
public string CustomConfig2Param1;
public string CustomConfig2Param2;
}
static class Program
{
static void Main()
{
var original = new CustomConfig1
{
appname = "foo",
CustomConfig1Param1 = "x",
CustomConfig1Param2 = "y"
};
var xml = Serialize(original);
var clone = DeserializeConfig(xml);
Console.WriteLine(clone.appname);
var typed = (CustomConfig1)clone;
Console.WriteLine(typed.CustomConfig1Param1);
Console.WriteLine(typed.CustomConfig1Param2);
}
public static string Serialize(Config obj)
{
using (var serialized = new StringWriter())
{
GetConfigSerializer().Serialize(serialized, obj);
return serialized.ToString();
}
}
public static Config DeserializeConfig(string xml)
{
using(var reader = new StringReader(xml))
{
return (Config)GetConfigSerializer().Deserialize(reader);
}
}
static Type[] GetKnownTypes()
{
// TODO: resolve types properly
return new[] { typeof(CustomConfig1), typeof(CustomConfig2) };
}
private static XmlSerializer configSerializer;
public static XmlSerializer GetConfigSerializer()
{
return configSerializer ?? (configSerializer =
new XmlSerializer(typeof(Config), GetKnownTypes()));
}
}