Can't Access my Object's Members - c#

Error : 'object' does not contain a definition for 'lp' and no extension method >'lp' accepting a first argument of type 'object' could be found (are you missing >a using directive or an assembly reference?
If I try and get a value form my object I get this...
But When I run without trying to get the value, I can clearly see my object does contain lp...
Full code for Deserialize...
public object Deserialize(Object obj, string path)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
StreamReader reader = new StreamReader(path);
obj = serializer.Deserialize(reader);
reader.Close();
return obj;
}
Person class...
public class Person
{
public string name { get; set; }
public int age { get; set; }
}
PersonList class...
public class PersonList
{
public List<Person> lp = new List<Person>();
public void AddPerson(Person p)
{
lp.Add(p);
}
}
It's an instance of the Person List I am sending in to public class PersonList
{
public List<Person> lp = new List<Person>();
public void AddPerson(Person p)
{
lp.Add(p);
}
}.
UPDATE: I was doing casting before but I will be passing in loads of different types of objects so wanted a generic Deserialize function. is there a way to do this? –

You updated your question with a request for a generic cast and Generics is exactly what you're looking for.
public T Deserialize<T>(T obj, string path)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StreamReader reader = new StreamReader(path);
obj = (T)serializer.Deserialize(reader);
reader.Close();
return obj;
}

Your obj variable is declared as object instance. Do cast in Deserialize:
var obj = (PersonList)serializer.Deserialize(reader);

Your obj have type of object, so you can use only general methods of object class. You should cast obj to the type you need. For example:
obj = (PersonList)serializer.Deserialize(reader);
obj = serializer.Deserialize(reader) as PersonLis;
You can also use is operator to check if your obj belongs to PersonList class

You could write an extension method for the XmlSerializer to use generic deserialization:
public static class Extension
{
public static T Deserialize<T>(this XmlSerializer serializer, StreamReader streamReader)
{
try
{
return (T) serializer.Deserialize(streamReader);
}
catch (InvalidCastException)
{
return default(T);
}
}
}
Then call it by:
XmlSerializer serializer = new XmlSerializer(obj.GetType());
StreamReader reader = new StreamReader(path);
var deserialized = serializer.Deserialize<PersonList>(reader);
reader.Close();

Related

NewtonSoft Inheretance deserialization of an JSON array Without altering the JSON

I have a simple use case where I want to deserialize a JSON that is basically an array of items, items are not identical but they all share a base class.
UPDATE:
my technical limitations:
I receive the JSON from a webhook and can't alter the serialization code or inject
any tokens in the source JSON
The Type property is the only information to do the correspondence between the derived class that I want to deserialize to
need strongly typed instances and not dynamic ones
The classes are in an assembly and I can't add any Json Annotations
Here is the code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var json = #" [{""Type"":0},{""Name"":""Derived"",""Type"":1}]";
var deserializedInstances = JsonConvert.DeserializeObject<List<BaseClass>>(json);
foreach(var e in deserializedInstances) {
if(e is BaseClass baseClass)
{
Console.WriteLine("Base Class , Type = {0}", baseClass.Type);
}else if(e is DerviedClass derivedClass)
{
Console.WriteLine("Derived Class , Type = {0}, Name = {1}", derivedClass.Type, derivedClass.Name);
}
}
// Output
// Base Class , Type = 0
// Base Class , Type = 0
}
public class BaseClass
{
public virtual int Type =>0;
}
public class DerviedClass: BaseClass
{
public string Name {get; set;}
public override int Type =>1;
}
}
so this code will produce this output:
// Base Class , Type = 0
// Base Class , Type = 0
but in my case, I want to have the instance of the derived class.
// Base Class , Type = 0
// Base Class , Type = 1, Name = "Derived"
What is the best way to achieve this in terms of performance?
As Jawad pointed out, you are deserializing to the BaseClass so the objects will also be of type BaseClass and not extend beyond that.
What you want to do is something akin to this answer: Json.net serialize/deserialize derived types?
The short answer is you have to account for settings when deserializing, more specifically Type Name handling. Copied from the answer:
Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };
JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);
This will allow the ability to deserialize into derived classes and alike. An example can be found here as well: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm
EDIT: In terms of performance I'm not sure there's a much better way of producing the same results that you are looking for.
Taking a detour over dynamic to strongly typed:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var a = new BaseClass(){ Type = 0 };
var b = new DerivedClass(){ Type = 1, Name = "Hello" };
var list = new List<BaseClass>(){a,b};
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
var intermediate = JsonConvert.DeserializeObject<List<dynamic>>(json);
var result = new List<object>();
foreach( dynamic item in intermediate )
{
// Of course, you surely could optimize the conversion:
if( item.Type == 0 ) result.Add( new BaseClass(){Type = item.Type});
if( item.Type == 1 ) result.Add( new DerivedClass(){Type= item.Type, Name= item.Name});
}
Console.WriteLine($"[{string.Join(", ",result)}]");
}
}
public class BaseClass
{
public int Type {get; set;}
}
public class DerivedClass: BaseClass
{
public string Name {get; set;}
}
produces output on fiddle:
[{"Type":0},{"Name":"Hello","Type":1}]
[BaseClass, DerviedClass]
Mind, that this is just a proof of concept. Of course, you'd need to fortify and find some decent algorithm to get from dynamic to your desired strong type.
Update
This fiddle shows some possibilities to improve on effort for many Derived Classes: https://dotnetfiddle.net/zECBx5
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
var a = new BaseClass(){ Type = 0 };
var b = new DerivedClass(){ Type = 1, Name = "Hello" };
var list = new List<BaseClass>(){a,b};
var json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
var intermediate = JsonConvert.DeserializeObject<List<dynamic>>(json);
var result = Construct( intermediate );
Console.WriteLine($"[{string.Join(", ",result.Select(x => x?.ToString() ?? "NULL"))}]");
}
public static List<object> Construct( List<dynamic> items )
{
var result = new List<object>();
Console.WriteLine( $"Processing {items.Count} dynamic items" );
foreach( dynamic item in items )
{
result.Add(Construct( item ));
}
return result;
}
private static Dictionary<int, Func<dynamic, object>> factoryMap = new () {
{0 , Construct<BaseClass>},
{1 , Construct<DerivedClass>},
};
public static object Construct( dynamic item )
{
Console.WriteLine($"Item Type = {item.Type}");
object result = null;
result = factoryMap[(int)item.Type](item);
return result;
}
public static TResult Construct<TResult>( dynamic item ) where TResult: class, new()
{
Console.WriteLine($"Constructing a {typeof(TResult).ToString()}");
TResult result = new();
foreach( var property in result.GetType().GetProperties() )
{
JObject jo = item as JObject;
var propVal = jo.Property(property.Name).ToObject(property.PropertyType);
Console.WriteLine($"Setting property {property.Name} to value {propVal}");
property.SetValue( result, propVal );
}
return result;
}
}
public class BaseClass
{
public int Type {get; set;}
}
public class DerivedClass: BaseClass
{
public string Name {get; set;}
}
Custom Converters is the solution I was looking for:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
var json = #" [{""Type"":0},{""Name"":""Derived"",""Type"":1}]";
var deserializedInstances = JsonConvert.DeserializeObject<List<BaseClass>>(json,
new JsonSerializerSettings()
{
Converters = { new CustomConverter() }
});
foreach(var e in deserializedInstances) {
if(e is BaseClass baseClass && e.Type == 0)
{
Console.WriteLine("Base Class , Type = {0}", baseClass.Type);
}
if(e is DerviedClass derivedClass)
{
Console.WriteLine("Derived Class , Type = {0}, Name = {1}", derivedClass.Type, derivedClass.Name);
}
}
// output
// Base Class , Type = 0
// Derived Class , Type = 1, Name = Derived
}
public class BaseClass
{
public int Type {get; set;}
}
public class DerviedClass: BaseClass
{
public string Name {get; set;}
}
public class CustomConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(BaseClass).IsAssignableFrom(objectType) || typeof(BaseClass) == objectType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo["Type"].Value<int>() == 0)
return new BaseClass() { Type = jo["Type"].Value<int>()}; // avoid stack overflow
if (jo["Type"].Value<int>() == 1)
return jo.ToObject<DerviedClass>(serializer);
return null;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}

How to serialize properties with DefaultValueAttribute using XmlSerializer?

I am using XmlSerializer to serialize C# objects to XML. I have DefaultValueAttribute on some of the properties of the classes I am trying to serialize, when I try to serialize them it seems that XmlSerializer does not include value in xml if it equals default value.
Look at this example:
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Test
{
public class Person
{
[System.Xml.Serialization.XmlAttribute()]
[System.ComponentModel.DefaultValue("John")]
public string Name { get; set; }
}
public static class Test
{
public static void Main()
{
var serializer = new XmlSerializer(typeof(Person));
var person = new Person { Name = "John" };
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw))
{
serializer.Serialize(writer, person);
var xml = sw.ToString();
}
}
}
}
}
It will produce the following xml (notice name attribute is not available):
<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
I cannot modify the source code of the classes so I CANNOT remove DefaultValueAttribute. Is there a way to make XmlSerializer serialize this properties without changing the source code?
You can do it by passing in an XmlAttributeOverrides instance to the XmlSerializer when you create it as below. You can either change the default value to something else using this, or set it to null to effectively remove it.
XmlAttributeOverrides attributeOverrides = new XmlAttributeOverrides();
var attributes = new XmlAttributes()
{
XmlDefaultValue = null,
XmlAttribute = new XmlAttributeAttribute()
};
attributeOverrides.Add(typeof(Person), "Name", attributes);
var serializer = new XmlSerializer(typeof(Person), attributeOverrides);
var person = new Person { Name = "John" };
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw))
{
serializer.Serialize(writer, person);
var xml = sw.ToString();
}
}
Update: the above means you have to provide other unrelated attributes again on each property you are changing. This is a bit of a chore if you have a lot of properties and just want to remove default for all of them. The class below can be used to preserve other custom attributes while only removing one type of attribute. It can be further extended if required to only do it for certain properties etc.
public class XmlAttributeOverrideGenerator<T>
{
private static XmlAttributeOverrides _overrides;
private static Type[] _ignoreAttributes = new Type[] { typeof(DefaultValueAttribute) };
static XmlAttributeOverrideGenerator()
{
_overrides = Generate();
}
public static XmlAttributeOverrides Get()
{
return _overrides;
}
private static XmlAttributeOverrides Generate()
{
var xmlAttributeOverrides = new XmlAttributeOverrides();
Type targetType = typeof(T);
foreach (var property in targetType.GetProperties())
{
XmlAttributes propertyAttributes = new XmlAttributes(new CustomAttribProvider(property, _ignoreAttributes));
xmlAttributeOverrides.Add(targetType, property.Name, propertyAttributes);
}
return xmlAttributeOverrides;
}
public class CustomAttribProvider : ICustomAttributeProvider
{
private PropertyInfo _prop = null;
private Type[] _ignoreTypes = null;
public CustomAttribProvider(PropertyInfo property, params Type[] ignoreTypes)
{
_ignoreTypes = ignoreTypes;
_prop = property;
}
public object[] GetCustomAttributes(bool inherit)
{
var attribs = _prop.GetCustomAttributes(inherit);
if (_ignoreTypes == null) return attribs;
return attribs.Where(attrib => IsAllowedType(attrib)).ToArray();
}
private bool IsAllowedType(object attribute)
{
if (_ignoreTypes == null) return true;
foreach (Type type in _ignoreTypes)
if (attribute.GetType() == type)
return false;
return true;
}
public object[] GetCustomAttributes(Type attributeType, bool inherit)
{
throw new NotImplementedException();
}
public bool IsDefined(Type attributeType, bool inherit)
{
throw new NotImplementedException();
}
}
}
Usage:
XmlAttributeOverrides attributeOverrides = XmlAttributeOverrideGenerator<Person>.Get();
var serializer = new XmlSerializer(typeof(Person), attributeOverrides);
I dont have enough reputation to comment on steve16351's answer. but I feel I improved upon his code a little bit.
My use case involved an XML schema file generated via XSD.exe provided by Microsoft, and a class was then generated from the schema file. So the class had all the DefaultValue tags on it from the schema. There was also many nested types created. So to make my code succinct, I modified the 'Generate' method to get the overrides for the top-level class, and all the ones beneath it. Then everything is returned in a single XmlAttributesOverrides object.
static XmlAttributeOverrideGenerator()
{
_overrides = Generate(typeof(T), new XmlAttributeOverrides());
}
private static XmlAttributeOverrides Generate(Type targetType, XmlAttributeOverrides Overrides)
{
foreach (var property in targetType.GetProperties())
{
if (property.CustomAttributes.Any( CA => CA.AttributeType == typeof(DefaultValueAttribute)))
{
XmlAttributes propertyAttributes = new XmlAttributes(new CustomAttribProvider(property, _ignoreAttributes));
Overrides.Add(targetType, property.Name, propertyAttributes);
}
else
{
Type propType = property.PropertyType;
if (propType.IsClass && !propType.IsValueType && !propType.IsEnum && !propType.IsPrimitive && !propType.IsSealed) // Check if this is a custom class
{
//If this is a nested class or other class type, generate its overrides as well
Generate(propType, Overrides);
}
}
}
return Overrides;
}

Using class name as method parameter and return type

I have an extension method for deserialization of an XDocument.
I use CarConfiguration as variable in this method, but I have another class configurations:
public static CarConfiguration Deserialize(this XDocument xdoc)
{
XmlSerializer serializer = new XmlSerializer(typeof(CarConfiguration));
using (StringReader reader = new StringReader(xdoc.ToString()))
{
CarConfiguration cfg = (CarConfiguration) serializer.Deserialize(reader);
return cfg;
}
}
class CarConfiguration
{
//car
}
class BikeConfiguration
{
//bike
}
So, there are 2 questions here:
Can I use class name as parameter for this method? Something like this:
static CarConfiguration Deserialize(this XDocument xdoc, class classname) {
var serializer = new XmlSerializer(typeof(classname));
Can I make this method generic for all required types(CarConfiguration, BikeConfiguration etc.)? I mean for example dependency of return type on input class:
static <classname> Deserialize(this XDocument xdoc, class classname) {
The key word in your question is generic, so yes you can do this by utilising C# generics. For example:
public static T Deserialize<T>(this XDocument xdoc)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(xdoc.ToString()))
{
T cfg = (T) serializer.Deserialize(reader);
return cfg;
}
}
And now you call it like this:
CarConfiguration x = xmlDocument.Deserialize<CarConfiguration>();

.NET get class name from String

I need to use this method :
public T DeserializeFromXmlString<T>(string xmlString)
{
var serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlString))
{
return (T)serializer.Deserialize(reader);
}
}
And to use it, I need to know the generic type T. Imagine that I have a class "Apple". I will use it like this:
var myapple= DeserializeFromXmlString<Apple>(someXmlString);
But I need to be able to remove this <Apple> and replacing it by something else considering that I have the string "Apple".The goal is to convert a string to be able to use it in this method as a generic type T.
Re-design your API to support non-generic cases:
public object DeserializeFromXmlString(Type targetType, string xmlString)
{
var serializer = new XmlSerializer(targetType);
using (TextReader reader = new StringReader(xmlString))
{
return serializer.Deserialize(reader);
}
}
public T DeserializeFromXmlString<T>(string xmlString)
{
return (T)DeserializeFromXmlString(typeof(T), xmlString);
}
Load type from string and use non-generic API:
var targetType = Type.GetType("YourTypeName", true);
var deserializedObj = DeserializeFromXmlString(targetType, yourXmlString);

Generic BinaryReader

I'm writing binary serialiser/deserialser to convert a number of object types to/from a byte stream. The objects represent API commands and their associated responses for a device connected by Bluetooth or USB. I'm using the BinaryWriter & BinaryReader to write/read to/from the stream.
The serialiser is easy. The properites to be serialised are tagged with an attribute that specifies the order in which they are to be written to the byte stream. I iterate through the properties using reflection and overload resolution handles picking the correct Write(...) method of the BinaryWriter.
The deserialiser is not quite so simple. Again I can iterate through the properites in the particular response class that I'm expecting to determine the types that need to be read from the stream. The tricky bit is picking the correct method to call on the BinaryReader to read the value I need. I've thought of two approaches.
A big switch statement that calls the correct ReadXXXX() method based on the type to be read.
Use the name of the type I need to build the name of the method I need in a string, and then invoke the method using relection.
Is there a simpler way I'm not thinking of? It's just a shame you can't do overload resolution based on the return type you want.
I've used option 1 (big switch statement) in a binary deserializer. A cleaner method could be something like:
{
object result;
BinaryReader ...;
foreach (var propertyInfo in ...)
{
Func<BinaryReader, object> deserializer;
if (!supportedTypes.TryGetValue(propertyInfo.PropertyType, out deserializer))
{
throw new NotSupportedException(string.Format(
"Type of property '{0}' isn't supported ({1}).", propertyInfo.Name, propertyInfo.PropertyType));
}
var deserialized = deserializer(reader);
propertyInfo.SetValue(result, deserialized, null);
}
}
private static Dictionary<Type, Func<BinaryReader, object>> supportedTypes = new Dictionary<Type, Func<BinaryReader, object>>
{
{ typeof(int), br => br.ReadInt32() },
// etc
};
Another option is to let the command classes themselves do the serialization:
interface IBinarySerializable
{
void Serialize(BinaryWriter toStream);
void Deserialize(BinaryReader fromStream);
}
Then in your commands:
abstract class Command : IBinarySerializable
{
}
class SomeCommand : Command
{
public int Arg1 { get; set; }
public void Serialize(BinaryWriter toStream)
{
toStream.Write(Arg1);
}
public void Deserialize(BinaryReader fromStream)
{
Arg1 = fromStream.ReadInt32();
}
}
And generic serialization methods:
void Serialize<T>(T obj) where T : IBinarySerializable
{
obj.Serialize(_stream);
}
T Deserialize<T>() where T : new(), IBinarySerializable
{
var result = new T();
result.Deserialize(_stream);
return result;
}
But this way you might end up duplicating some code. (On the other hand, derived classes can call their parent class versions of Serialize/Deserialize if that makes sense in your scenario, and that works nicely.)
I do not know if I fully understand what you are trying to do. But it very much sound like you shall take a closer look at the BinaryFormatter and its serialization surrogates in .NET. The BinaryFormatter let you easily Serialize and Deserialize objects and the serialization surrogates let you add your custom serialization and deserialization logic and also make it possible to remapp one object to antoher.
Take a look here:
BinaryFormatter
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx
ISerializationSurrogate
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate.aspx
SurrogateSelector
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector.aspx
SerializationBinder
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder.aspx
You can also see a small example here, where I have a method that can serialize any object to a base64 encoded string, and then a deserialize-method that can deserialize this string. I also add a SerializationBinder to the formatter that remapp the serialization of the type MyOldClass to the type MyNewClass and also add a custom ISerializationSurrogate that can process the values of the fields in the object before it is added to the ner class.
public class SerializeDeserializeExample {
public string Serialize(object objectToSerialize) {
using(var stream = new MemoryStream()) {
new BinaryFormatter().Serialize(stream, objectToSerialize);
return Convert.ToBase64String(stream.ToArray());
}
}
public object Deserialize(string base64String) {
using(var stream = new MemoryStream(Convert.FromBase64String(base64String))) {
var formatter = new BinaryFormatter();
var surrogateSelector = new SurrogateSelector();
formatter.SurrogateSelector = surrogateSelector;
formatter.Binder = new DeserializationBinder(surrogateSelector);
return formatter.Deserialize(stream);
}
}
}
public class MyDeserializationBinder : SerializationBinder {
private readonly SurrogateSelector surrogateSelector;
public MyDeserializationBinder(SurrogateSelector surrogateSelector) {
this.surrogateSelector = surrogateSelector;
}
public override Type BindToType(string assemblyName, string typeName) {
if(typeName.Equals("MyOldClass", StringComparison.InvariantCultureIgnoreCase)) {
return RemapToType();
}
return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
}
private Type RemapToType() {
var remapToType = typeof(MyNewClass);
surrogateSelector.AddSurrogate(remapToType,
new StreamingContext(StreamingContextStates.All),
new MyCustomDeserializationSurrogate());
return remapToType;
}
}
public sealed class MyCustomDeserializationSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context) {
throw new NotImplementedException();
}
public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
var objectType = obj.GetType();
var fields = GetFields(objectType);
foreach(var fieldInfo in fields) {
var fieldValue = info.GetValue(fieldInfo.Name, fieldInfo.FieldType);
fieldValue = DoSomeProcessing(fieldValue);
fieldInfo.SetValue(obj, fieldValue);
}
return obj;
}
private static IEnumerable<FieldInfo> GetFields(Type objectType) {
return objectType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
private static object DoSomeProcessing(object value){
//Do some processing with the object
}
}

Categories