XML Serialisation question - c#

I'm trying to teach-myself how to serialize/deserialize to/from XML using the attribute-based serializer. I've put the below code together for testing purposes but it seems that I might have missed a point or two. Can anyone assist me and tell me what to do to have the whole damn thing work properly? The code below should compile and run just fine but will throw an exception - something is probably wrong with my attributes.
What did I miss?
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
namespace XMLSerialisation_test
{
class Program
{
static void Main(string[] args)
{
World my_world = new World(new Point(20, 30));
for (int i = 0; i < 10; i++)
{
string property = String.Format("Property no.{0}", i);
my_world.PushWorldObject(new MyObject(new Point(i, i), property));
}
DataContractSerializer world_serializer = new DataContractSerializer(typeof(World));
try
{
using (Stream s = File.Create("output.xml"))
world_serializer.WriteObject(s, my_world);
}
catch (Exception e)
{
Console.WriteLine("Exception occured : {0}", e.Message);
}
}
}
}
WorldObject.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace XMLSerialisation_test
{
[DataContract]
public struct Point // couldn't find the pre-defined Point for some reason
{
public Point(double x, double y)
{ X = x; Y = y; }
[DataMember]
public double X;
[DataMember]
public double Y;
}
[DataContract]
public abstract class WorldObject
{
public WorldObject() : this(0.0, 0.0)
{}
public WorldObject(Point loc)
{ m_location = loc; }
public WorldObject(double x, double y)
{
m_location.X = x;
m_location.Y = y;
}
[DataMember]
public Point Location
{
get { return m_location; }
set { m_location = value; }
}
protected Point m_location;
}
[DataContract]
public class MyObject : WorldObject
{
public MyObject(string prop)
: base(0.0, 0.0)
{ m_property = prop; }
public MyObject(Point p, string prop)
: base(p)
{ m_property = prop; }
[DataMember]
public string Property
{
get{ return m_property; }
set{ m_property = value; }
}
private string m_property;
}
}
World.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace XMLSerialisation_test
{
[DataContract]
class World
{
public World() : this(new Point(10, 10))
{ }
public World(Point size)
{ m_world_size = size; }
public bool PushWorldObject(WorldObject o)
{
try
{
WorldObjects.Add(o);
return true;
}
catch(Exception e)
{
Console.WriteLine("Exception occured : {0}", e.Message);
return false; }
}
#region Accessors
[DataMember]
public List<WorldObject> WorldObjects
{
get { return m_world_objects; }
set { m_world_objects = value; }
}
[DataMember]
public Point WorldSize
{
get { return m_world_size; }
private set { m_world_size = value; }
}
#endregion
#region Fields
private List<WorldObject> m_world_objects = new List<WorldObject>();
private Point m_world_size;
#endregion
}
}

Try this:
DataContractSerializer world_serializer = new DataContractSerializer(typeof(World), new List<Type> { typeof(MyObject) });
The problem is that PushWorldObject takes type WorldObject, but you are actually passing type MyObject. The serializer knows nothing about this type, so throws an exception. WorldObject is used within the World class, so this type is by known by default. However, MyObject is not used inside World - so you manually have to declare it as Known.
As an alternative, you can add the KnownType attribute like so:
[DataContract, KnownType(typeof(MyObject))]
class World
{

The biggest problem I see is the abstract WorldObject. You'll need to use a KnownType attribute there (or via config or method name- check MSDN for "Data Contract Known Types") to tell it about the known subtypes it might encounter (eg, MyObject).

Just to clarify: if you are serializing to xml for the purposes of having xml in a known format, then DataContractSerializer is a bad choice; you would do better to use XmlSerializer, which has more control over xml layout. You would use the [XmlElement] / [XmlAttribute] / [XmlType] / [XmlRoot] attributes instead of [DataMember] etc.
If you just want to use xml because it is text and stores the object, then DataContractSerializer is fine; and has other advantages, for example - not demanding a public parameterless constructor (which XmlSerializer does), and working with private members (which XmlSerializer doesn't).

Related

C# XML serialize and deserialize one enum into another enum with the same attributes

Let's say I have a library with the following enum attributes:
public enum LibraryAuth
{
Online,
Offline,
}
This enum is being used in an Object of the library.
Now I have my own enum which goes like this:
[Serializable, XmlType]
public enum MyAuth
{
[XmlEnum]
Online,
[XmlEnum]
Offline,
}
This one is supposed to be used within a class of my own programm:
[Serializable, DebuggerStepThrough, DesignerCategory("code"), GeneratedCode("WebServiceProxyUpdater", "1.0.0.0"), XmlType]
public class MyClass
{
[XmlAttribute]
public MyAuth auth { get; set; }
}
The object of the library and my object have the same attributes.
Now I am trying to cast the object of the library into the object of my program with this function:
public static destT CreateCopy<sourceT, destT>(sourceT sourceObj)
{
try
{
XmlSerializer sourceXS = new XmlSerializer(typeof(sourceT));
XmlSerializer destXS = new XmlSerializer(typeof(destT));
using (MemoryStream ms = new MemoryStream())
{
sourceXS.Serialize(ms, sourceObj);
ms.Position = 0;
return (destT)destXS.Deserialize(ms);
}
}
catch (Exception ex)
{
return default(destT);
}
}
Unfortunately this throws the following error: Instance validation error: '' is not a valid value for MyAuth
If I replace my enum with the enum of the library the serialisation works just fine. But somehow serializing it with my enum does not work.
What am I missing in my Enum Class?
EDIT: I've read about a similar problem in this thread but the OP in that thread wanted to ignore the error. I on the other hand want to cast one object into another.
Locally, this works just fine and does not show the error you report. My changes:
made MyClass be public
added a LibraryClass that mimics the source type; note in particular the use of [XmlRoot]
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
static class P
{
static void Main()
{
var obj = new LibraryClass { auth = LibraryAuth.Offline };
var foo = CreateCopy<LibraryClass, MyClass>(obj);
Console.WriteLine(foo.auth);
}
public static destT CreateCopy<sourceT, destT>(sourceT sourceObj)
{
XmlSerializer sourceXS = new XmlSerializer(typeof(sourceT));
XmlSerializer destXS = new XmlSerializer(typeof(destT));
using (MemoryStream ms = new MemoryStream())
{
sourceXS.Serialize(ms, sourceObj);
ms.Position = 0;
return (destT)destXS.Deserialize(ms);
}
}
}
public enum LibraryAuth
{
Online,
Offline,
}
[XmlRoot("MyClass")] // the two types must agree on naming
public class LibraryClass
{
[XmlAttribute]
public LibraryAuth auth { get; set; }
}
[Serializable, XmlType]
public enum MyAuth
{
[XmlEnum]
Online,
[XmlEnum]
Offline,
}
[Serializable, DebuggerStepThrough, DesignerCategory("code"), GeneratedCode("WebServiceProxyUpdater", "1.0.0.0"), XmlType]
public class MyClass
{
[XmlAttribute]
public MyAuth auth { get; set; }
}

Cannot convert from 'Program.state<TState>' to 'Program.state<object>' passing custom type to class in a dictionnary

I'm working on a lightweight state system for my app.
I'm kinda confused:
how can I pass type to my class in a dictionary?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class Program
{
public class state<TState>
{
private TState? _value;
public TState Value { get { return _value; } set { if (!_value.Equals(value)) _value = value;if(onChange != null ) onChange(Value); } }
private Action<TState>? onChange;
public state(TState val, Action<TState>? action)
{
_value = val;
onChange = action;
}
}
public class stateHolder
{
public Dictionary<string, object> states = new();
public void AddState<TState>(string name, TState value, Action<TState>? onChange)
{
state<TState> state = new state<TState>(value, onChange);
states[name] = state;//ERROR HERE
}
public object? this[string stateName] { get{ return states[stateName];} }
}
public static void Main()
{
stateHolder states = new();
states.AddState<string>("test","Yeah",(x)=>Console.WriteLine(x));
state<string> test = states["test"] as state<string>;
test.Value = "Hey";//should console log Hey
Console.WriteLine("Hello World");
test.Value = "Hello";//should console log Hey
}
}
I'm not a beginner, but not a pro at all. I code when I have freetimes so sorry if my code is dumb if you can help me would be nice thanks in advance links bottom
Fiddle link https://dotnetfiddle.net/GxdLGb
Collab link https://dotnetfiddle.net/GxdLGb#&togetherjs=G2ED70iyE8

Get field values from class within class

This has been driving me mad for a while now. I have a class which contains other classes. I need to loop through the first class looking for typeof second class then retreive the value of the fields.
the below code obviously fails on the line
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
as this isn't a valid field. Possibly I'm going about this the wrong way - any ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
MyFirstClass mFC = new MyFirstClass();
FieldInfo[] fI = mFC.GetType().GetFields();
foreach (FieldInfo field in fI)
{
if (field.FieldType.Name == "MySecondClass")
{
//get the fields
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
}
}
}
}
class MyFirstClass
{
public MySecondClass firstMSC = new MySecondClass("First Instance");
public MySecondClass secondMSC = new MySecondClass("Second Instance");
public string firstClassString = "I'm from the first class";
public int firstClassInt = 5;
}
class MySecondClass
{
public MySecondClass(string input)
{
this.secondClassString = input;
}
public string secondClassString;
public int secondClassInt = 10;
}
}
field.GetValue accepts the instance from which it gets the field value.
In your case I would expect it should be field.GetValue(mFC).
Also field.FieldType.Name == "MySecondClass" is not the best way to check the type as type name change will cause code to break. I recommend replacing it with field.FieldType == typeof(MySecondClass).
((MySecondClass)field.GetValue(mFC)).secondClassString;
use this inside console.writeline

Ninject factory not working with conventions for me

I am trying to use the method of binding located here but having no luck
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Keep in mind I am not trying to do it this way:https://gist.github.com/akimboyko/4593576
Rather I am trying to use the convention GetMercedes() to mean
I am basically trying to achieve this:https://gist.github.com/akimboyko/4593576 with conventions specified in the above examples.
using Ninject;
using Ninject.Extensions.Factory;
using Ninject.Modules;
using Ninject.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Test.NinjectFactory
{
public class Program
{
public static void Main()
{
using (var kernel = new StandardKernel(new CarModule()))
{
var factory = kernel.Get<ICarFactory>();
var mercedes =factory.GetMercedes();
int i = 1;
}
}
public interface ICar
{
void Drive();
}
public class Mercedes : ICar
{
readonly ICarFactory carFactory;
public Mercedes(ICarFactory carFactory)
{
this.carFactory = carFactory;
}
public void Drive()
{
var Mercedes = this.carFactory.GetMercedes();
}
}
public interface ICarFactory
{
ICar GetMercedes();
}
public class CarModule : NinjectModule
{
public override void Load()
{
//https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Kernel.Bind<ICarFactory>().ToFactory();
Bind<ICar>().To<Mercedes>().NamedLikeFactoryMethod<ICarFactory>(x => x.GetMercedes());//doesnt work for me
}
}
}
}
I'm posting this as an answer because it is most likely the cause.
The factory extensions use prefixed Get methods as a standard. You'll run into issues by calling any of your factory methods with prefixed Get and using NamedLikeFactoryMethod. For example, GetFord, GetMercedes, GetNissan. You'll notice that, in the example at the link you provided, the function is called CreateMercedes.
Change your function name to CreateMercedes or anything that doesn't start with Get and it should be fine.
I found the anwswer here:
https://gist.github.com/akimboyko/5338320
It seems you need a function to take care of the binding
public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
{
string.Format("Binds '{0}' to '{1}' as '{2}", type, type.Name, typeof(InterfaceType)).Dump();
yield return bindingRoot.Bind(typeof(InterfaceType))
.To(type)
.Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
}
}
}

Representing multiple values within one class member

I've been working on some electrical network simulation software (ElecNetKit). In electrical networks, sometimes it's convenient to work with single-phase models, sometimes in three-phase models.
As such, I would like to be able to represent one of the electrical network elements as:
class Bus
{
public Complex Voltage {set; get;} //single phase property
}
but simultaneously in a fashion so that the user can call Bus.Voltage.Phases[x], and expect a Complex for any valid integer x.
The Bus.Voltage property should map to Bus.Voltage.Phases[1] when treated as a Complex.
I've got two questions here:
Is this in violation of any OOP principles? I've got a feeling that it might be.
Is there a convenient way to represent this in C#?
In terms of representation, I've tried:
a class Phased<T> : T, but this is incompatible with the typing system, and
a class Phased<T> with a generic converter to type T, but the converter still needs to be invoked.
I'm aware that I can simply use something like:
public Dictionary<int,Complex> VoltagePhases {private set; get;}
public Complex Voltage {
set {VoltagePhases[1] = value;}
get {return VoltagePhases[1];}
}
but there's a lot of repetition once you start to do this for multiple properties, across multiple classes.
I would propose something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Numerics;
namespace Test
{
class PhaseList
{
private Dictionary<int, Complex> mPhases = new Dictionary<int, Complex>();
public Complex this[int pIndex]
{
get
{
Complex lRet;
mPhases.TryGetValue(pIndex, out lRet);
return lRet;
}
set
{
mPhases.Remove(pIndex);
mPhases.Add(pIndex, value);
}
}
}
class PhasedType
{
private PhaseList mPhases = new PhaseList();
public PhaseList Phases { get { return mPhases; } }
public static implicit operator Complex(PhasedType pSelf)
{
return pSelf.Phases[1];
}
public static implicit operator PhasedType(Complex pValue)
{
PhasedType lRet = new PhasedType();
lRet.Phases[1] = pValue;
return lRet;
}
}
class Bus
{
public PhasedType Voltage { get; set; }
}
class Program
{
static void Main(string[] args)
{
Bus lBus = new Bus();
lBus.Voltage = new Complex(1.0, 1.0);
Complex c = lBus.Voltage;
lBus.Voltage.Phases[1] = c;
c = lBus.Voltage.Phases[1];
}
}
}
Can you do something like this? This will work similar to your solution at the bottom but because of the generic class you are not repeating the code for each property.
class Program
{
static void Main(string[] args)
{
Collection<Complex> complex = new Collection<Complex>();
//TODO: Populate the collection with data
Complex first = complex.First;
Complex another = complex.Items[2];
}
}
public class Complex
{
// implementation
}
public class Collection<T> where T : class
{
public List<T> Items { get; set; }
public T First
{
get
{
return (Items.Count > 0) ? Items[1] : null;
}
set
{
if(Items.Count > 0)
Items[1] = value;
}
}
}

Categories

Resources