How to deserialize xml to object with inheritance? - c#

I have the following xml which represents 2 types of plugins, FilePlugin and RegsitryPlugin:
<Client>
<Plugin Type="FilePlugin">
<Message>i am a file plugin</Message>
<Path>c:\</Path>
</Plugin>
<Plugin Type="RegsitryPlugin">
<Message>i am a registry plugin</Message>
<Key>HKLM\Software\Microsoft</Key>
<Name>Version</Name>
<Value>3.5</Value>
</Plugin>
</Client>
I would like to deserialize the xml into objects.
As you can see, the 'Message' element is repeating itself both for the FilePlugin and the RegistryPlugin and i am using inheritance for this:
abstract class Plugin
{
private string _message;
protected Plugin(MISSING conf)
{
// here i need to set my private members like:
// Message = MISSING.Message;
}
}
class FilePlugin : Plugin
{
private string _path;
public FilePlugin(MISSING config)
: base(config)
{
// Here i need to set my private members like:
// _path = config.Path;
}
}
class RegistryPlugin : Plugin
{
private string _key;
private string _name;
private string _value;
public RegistryPlugin(MISSING config)
: base(config)
{
// Here i need to set my private members like:
// _key = config.Key;
// _key = config.Name;
// _key = config.Value;
}
}
}
I need somehow to deserialize the xml, and than to decide according the PluginType Element which Instance to create:
i.e:
if it is written in the xml the Type=FilePlugin than i need to create
Plugin p1 = new FilePlugin(conf);
if it is written in the xml the Type=RegistryPlugin than i need to create
Plugin p2 = new RegistryPlugin(conf);
Please follow my comments in my code in order to understand the missing parts.
Thanks

Creating your own deserializer isn't also hard. Here is my solution to this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Xml.Linq;
using System.Reflection;
using System.Text;
namespace WindowsFormsApplication1
{
public abstract class Plugin
{
public string Type { get; set; }
public string Message { get; set; }
}
public class FilePlugin : Plugin
{
public string Path { get; set; }
}
public class RegsitryPlugin : Plugin
{
public string Key { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
static class MyProgram
{
[STAThread]
static void Main(string[] args)
{
string xmlstr =#"
<Client>
<Plugin Type=""FilePlugin"">
<Message>i am a file plugin</Message>
<Path>c:\</Path>
</Plugin>
<Plugin Type=""RegsitryPlugin"">
<Message>i am a registry plugin</Message>
<Key>HKLM\Software\Microsoft</Key>
<Name>Version</Name>
<Value>3.5</Value>
</Plugin>
</Client>
";
Assembly asm = Assembly.GetExecutingAssembly();
XDocument xDoc = XDocument.Load(new StringReader(xmlstr));
Plugin[] plugins = xDoc.Descendants("Plugin")
.Select(plugin =>
{
string typeName = plugin.Attribute("Type").Value;
var type = asm.GetTypes().Where(t => t.Name == typeName).First();
Plugin p = Activator.CreateInstance(type) as Plugin;
p.Type = typeName;
foreach (var prop in plugin.Descendants())
{
type.GetProperty(prop.Name.LocalName).SetValue(p, prop.Value, null);
}
return p;
}).ToArray();
//
//"plugins" ready to use
//
}
}
}

My idea:
Add methods ToXml and FromXml to Plugin, and lets this method implementation in Plugin load/save only common properties like Message in your example;
Override these methods in derived classes, and call base methods in overridden ones to load common parameters, as well as add custom code to load specific parameters.
Create static method in LoadXml in Plugin that reads XML file, gets type name, creates this type instance dynamically with reflection and calls its FromXml method.

You may use what is called a "memento pattern".
The idea is that you have some extra object especially for serialization-deserialization.
So you may have something like:
public class PluginMemento {
[XmlAttribute] public string Type { get; set; }
[XmlElement] public string Name { get; set; }
[XmlElement] public string Message { get; set; }
[XmlElement] public string Key { get; set; }
..... //all the other properties
}
[XmlRootAttribute("Client")]
public class Client {
[XmlElementAttribute("Plugin")]
public PluginMemento[] plugins;
}
Now you should be able to deserialize your Xml into the Client type.
Then you can enumerate plugins, and start creating instances based on PluginMemento.Type property (via reflection, or by using a factory or a factory method) by passing the PluginMemento into the constructor of the class specified in the Type property.
The factory method can be very simple:
public static Plugin CreatePlugin(PluginMemento memento) {
switch(memento.Type) {
case "FirstPlugin": return FirstPlugin(memento);
case "SecondPlugin": return SecongPlugin(memento);
}
}
Reflection may be more smart and interesting, but requires a bit more coding.

I would implement the Factory Pattern with a Class which produces you the concrete Plugin.

Related

associate a string with a class so that I can retrieve the string if class is given as generic type parameter

For different classes I need to attach a string to the class (i.e. Class1 has the string hello, Class2 has the string world etc.). Then I will have a generic type parameter T somewhere that will be (at runtime) one of these classes. I need to be able to retrieve the associated string from that generic type parameter.
How do I set this up and make it work?
Since all classes are written by me, I can use every possible approach (e.g. define common interface for them or common base class or whatever).
I tried creating a base class that has a public static field containing the string, and for each actual class "overwrite" (hide base and create new) the string. But it turned that I still could not retrieve the string when only having the type parameter T.
public class BaseClass
{
public static string Get => "";
}
public class Class1 : BaseClass
{
public static new string Get => "hello";
}
public class Class2 : BaseClass
{
public static new string Get => "world";
}
public class Testing<T> where T : BaseClass
{
public void Test()
{
string s = T.Get;
// compiler error: "'T' is a type parameter, which is not valid in the given context"
// strangely though, BaseClass.Get and Class1.Get and Class2.Get work fine!
}
}
Real-world use case:
I have a static class MySerializer<T> that is supposed to deserialize objects of type T. During deserialization I want to validate if my object of type T conforms to the schema associated with type T.
In order to validate I need to add a schema first. For each class T that can be deserialized there is a different schema which I store in my project as an embedded resource, so each schema has a path (like a file path). That means: for each class T I need to associate a string (the path) with the class so that I am able to get that path out of T.
Here is the relevant part of my serializer and the schema adding process:
public static class MySerializer<T>
{
private static readonly XmlSerializer _mySerializer = new XmlSerializer(typeof(T));
private static readonly XmlReaderSettings _settings = new Func<XmlReaderSettings>(() =>
{
System.Reflection.Assembly assy = typeof(MySerializer<T>).Assembly;
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(null,
XmlReader.Create(assy.GetManifestResourceStream(T.GetAssociatedString())));
// T.GetAssociatedString(): How to make this work?
return new XmlReaderSettings
{
Schemas = schemas,
ValidationType = ValidationType.Schema,
ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings |
XmlSchemaValidationFlags.ProcessIdentityConstraints
};
})();
public static T Deserialize(Stream strm)
{
using (XmlReader reader = XmlReader.Create(strm, _settings))
{
return (T)_mySerializer.Deserialize(reader);
}
}
}
Since static methods and generic type parameters don't work together in C# (thanks to Matthew Watson for linking to Eric Lippet's Blog) and I don't want to create a new instance of T solely to be able to call a method, I'll go with attributes.
[AttributeUsage(AttributeTargets.Class)]
class SomeStringAttribute : Attribute
{
public string SomeString { get; set; }
public SomeStringAttribute(string s)
{
SomeString = s;
}
}
[SomeString("hello")]
public class Class1
{
}
[SomeString("world")]
public class Class2
{
}
public class Testing<T>
{
public void Test()
{
string s =
((SomeStringAttribute)typeof(T).GetCustomAttributes(typeof(SomeStringAttribute),
false)[0]).SomeString;
}
}
You could use reflection to do this, but note that all the properties need to be static (your sample code above introduces non-static properties to the derived class).
Here's a compilable example:
using System;
namespace Demo
{
public class BaseClass
{
public static string Get => "";
}
public class Class1 : BaseClass
{
public new static string Get => "hello";
}
public class Class2 : BaseClass
{
public new static string Get => "world";
}
public class Testing<T> where T : BaseClass
{
public string Test()
{
var property = typeof(T).GetProperty("Get");
if (property != null)
return (string) property.GetValue(null, null);
return null;
}
}
class Program
{
static void Main()
{
var test1 = new Testing<Class1>();
Console.WriteLine(test1.Test()); // Prints "hello"
var test2 = new Testing<Class2>();
Console.WriteLine(test2.Test()); // Prints "world"
}
}
}
In this code, the where T : BaseClass isn't actually needed for it to compile and work, but you might want to keep it to make it clear that it is only supposed to be used with classes that inherit from BaseClass.

Dealing with badly designed models from third party API

In company I work for I am forced to use badly designed models from the third party API I have no access to like:
class Player
{
object Id;
object Name;
}
Each time I use these properties I have to cast them to specific type.
var name = player.Name.ToString();
var id = (int)player.Id;
And I have to lookup the database what the type is.
I was thinking to create exactly the same classes and using something like AutoMapper to map it to my own type each time and create some proxies/wrapper classes over the original ones.
Any solution?
There are two ways I would do this. Either using an extension method or by simply creating your new class with a static Convert method that take the badly designed class as a parameter.
Example 1:
namespace ExcellentDesignedClasses
{
public class NewPlayerClass
{
public NewPlayerClass(int id, string name)
{
Id = id;
Name = name;
}
public static NewPlayerClass Convert(Player player)
{
return new NewPlayerClass((int)player.Id, (string)player.Name);
}
public int Id { get; set; }
public string Name { get; set; }
}
}
Example 2: using Extension Methods
namespace ExcellentDesignedClasses
{
public class NewPlayerClass
{
public NewPlayerClass(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
}
namespace ExcellentDesignedClasses.Extensions
{
public static class Extensions
{
public static NewPlayerClass ConvertToNew(this Player player)
{
return new NewPlayerClass((int)player.Id, (string)player.Name);
}
}
}
namespace MyProgram
{
using ExcellentDesignedClasses.Extensions;
public class Main
{
public void DoSomething()
{
var oldClassStructure = new Player();
var newClassStructure = oldClassStructure.ConvertToNew();
}
}
}
One thing you could do is create an extension method for the properties you care about. The nice thing is it's less work up front: just create an extension method when you find yourself needing to do a cast. You don't have to write any full classes or mapping code. The downside is you have to call a method every time you need a strongly typed property.
For example:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static string GetName(this Player p)
{
return p.Name?.ToString();
}
public static int GetId(this Player p)
{
return Convert.ToInt32(p.Id);
}
}
}
Then your code would look like:
string name = player.GetName();
int id = player.GetId();
I've worked for companies like this. They're the kind that still ask you in the interview if you know .Net, and you find out they mean version 1.1 on an old instance of Server 2003 they need maintained. They're the burnt raisins in the Raisin Bran.
Use inheritance to redefine the craptastic models. That's how I usually fix it. Then, I return what I want from my objects and stop using the classes I based them on.
ex:
class Player
{
public object Id;
public object Name;
}
class UserPlayer : Player
{
public new int Id
{
get
{
return Convert.ToInt32(base.Id);
}
set
{
base.Id = value;
}
}
public new string Name
{
get
{
return base.Name.ToString();
}
set
{
base.Name = value;
}
}
}
A runner up idea for when doing the above will get you in trouble because the person who wrote the code still works for the company and has friends or is, worse, your boss: use a static class to process what you want.
public static class ProcessPlayers
{
public static int ID(Player p)
{
return Convert.ToInt32(p.Id);
}
public static string Name(Player p)
{
return p.Name.ToString();
}
}
You can also just make new objects that each wrap around Player by having a Player as a property, but inheriting the object and overriding its properties is likely the better choice.

XML Element Name from T in Generic Class

For a current project I am trying to make have a generic XML creator using the XmlSerializer class - I need a certain element in one of the classes to have the ElementName set based on the type of class that the creator is in in this context that is simple enough. Here is an example:
public abstract class ElementTypeBase
{
public abstract string ElementName { get; }
}
public class ElementTypeA : ElementTypeBase
{
public override string ElementName
{
get { return "ElementA"; }
}
}
Then pass this to my XML object class which will be used for the XmlSerializer but I want the ElementName to be specific to the type.
public class XMLObject<T> where T : ElementTypeBase
{
[XmlElement(Activator.CreateInstance<T>().ElementName)]
public string SomeElement;
}
I thought I would be able to do that but get:
An attribute argument must be a constant expression, typeof expression
or array creation expression of an attribute parameter type
So I thought that I could override ToString() but this doesn't work, I was thinking of using constants but it feels dirty. Any other suggestions?
You can do that through the XmlAttributeOverrides class like shown below.
However, you'll need to cache the XmlSerializer instance and I wouldn't recommend this approach for your problem.
when you say that you have one element that is gonna be different for each inherited object, I'd suggest to put this element in the inherited class, not the generic one, and hard-code its XmlElement.ElementName.
using System;
using System.Xml.Serialization;
public class Program
{
static void Main(string[] args)
{
XmlSerializer serializer =
new XmlSerializer(typeof(XMLObject<MyElement>),
XMLObject<MyElement>.Overrides);
serializer.Serialize(Console.Out,
new XMLObject<MyElement>() { SomeElement = "value" });
Console.ReadLine();
}
}
public class XMLObject<T> where T : ElementTypeBase, new()
{
public static XmlAttributeOverrides Overrides { get; private set; }
static XMLObject()
{
Overrides = new XmlAttributeOverrides();
Overrides.Add(typeof(XMLObject<T>), "SomeElement",
new XmlAttributes
{
XmlElements =
{
new XmlElementAttribute(new T().ElementName)
}
});
}
public string SomeElement { get; set; }
}
public abstract class ElementTypeBase
{
public abstract string ElementName { get; }
}
public class MyElement : ElementTypeBase
{
public override string ElementName
{
get { return "ElementA"; }
}
}

Problem with XML serialisation and C#

I am trying to serialise some C# classes to XML. Things were going fine until I tried to introduce some inherited classes.
The classes are [edited for size]
public class ParticipationClass
{
[XmlAttribute]
public string typeCode;
[XmlAttribute]
public string contextControlCode;
public ParticipationClass()
{
}
}
public class p_recordTarget : ParticipationClass
{
public p_recordTarget()
{
typeCode = "RCT";
contextControlCode = "OP";
}
}
when using the classes the following code is used :
public class Test
{
// other class attributes excluded..
[XmlElement]
public ParticipationClass recordTarget;
private void Test()
{
recordTarget = new p_recordTarget();
}
}
The serialisation fails with an InvalidOperationException, looking in the exception detail I can see "Message="The type itk.cda.cdaclasses.p_recordTarget was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."
So I guess I need an XmlInclude, but I am not sure how.
In a nutshell, you need to use the attribute on the base class to let the serializer know about the derived classes:
[XmlInclude(typeof(p_recordTarget))]
public class ParticipationClass {
// ...
}
This may help you out:
http://www.codeproject.com/KB/XML/xmlserializerforunknown.aspx
Like this:
[XmlInclude(typeof(p_recordTarget))]
public class ParticipationClass
{
[XmlAttribute]
public string typeCode;
[XmlAttribute]
public string contextControlCode;
public ParticipationClass()
{
}
}

No base class problem, How to use Castle.DynamicProxy Mixin in this particular case?

I have a 3rd party badly designed library that I must use.
It has all sorts of types it works with, we'll call them SomeType1, SomeType2 etc.
None of those types share a common base class but all have a property named Value with a different return type.
All I want to do is to be able to Mixin this class so I'll be able to call someType1Instance.Value and someType2Instance.Value without caring what the concreate type it is and without caring what the return type is (I can use object).
So my code is currently:
public interface ISomeType<V>
{
V Value {get; set;}
}
public interface ISomeTypeWrapper
{
object Value { get; set; }
}
public class SomeTypeWrapper<T> : ISomeTypeWrapper
where T : ISomeType<???>
{
T someType;
public SomeTypeWrapper(T wrappedSomeType)
{
someType = wrappedSomeType
}
public object Value
{
get { return someType.Value; }
set { someType.Value = value != null ? value : default(T); }
}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
The problem is that I don't know what T might be until runtime due to the fact that I get a dictionary of objects.
I can iterate the dictionary and use reflection to create a SomeWrapperType on runtime but I would like to avoid it.
How can I mixin the concreate type of SomeType to ISomeType?
How can I know what V type parameter is? (wish I had typedefs and decltype like in c++)
How can I, with the minimum of use of reflection possible Mixin those classes with the interface/base class?
You could try the Duck Typing Extensions for Windsor. It means you will need to register each of your types.
container
.Register(Component.For(typeof(SomeType1)).Duck<ISomeType>())
.Register(Component.For(typeof(SomeType2)).Duck<ISomeType>());
You could probably use linq and the register AllTypes syntax to reduce code if the names are similar.
Alternatively in the short term create a factory which can return you the objects you need, implement a concrete object for each type. No you are using the interface you can remove the factory at a later date and replace it with something else with minimal impact:
public class SomeTypeWrapperFactory
{
public ISomeType<int> CreateWrapper(SomeType1 someType1)
{
return new SomeType1Wrapper(someType1);
}
public ISomeType<string> CreateWrapper(SomeType2 someType2)
{
return new SomeType2Wrapper(someType2);
}
}
public class SomeType1Wrapper : ISomeType<int> { ... }
public class SomeType2Wrapper : ISomeType<int> { ... }
Regardless of how you implement the wrapper, be the individually or using a god like class you have the ability to change how the wrapping is done and keep the rest of your code clean.
Why SomeTypeWrapper but not SomeObjectWrapper?
public class SomeObjectWrapper : ISomeType
{
Object _someObject;
PropertyInfo _valuePropertyInfo;
public SomeObjectWrapper(Object wrappedSomeObject)
{
_someObject = wrappedSomeObject;
_valuePropertyInfo = _someObject.GetType().GetProperty("Value", System.Reflection.BindingFlags.Public);
}
public object Value
{
get { return _valuePropertyInfo.GetValue(_someObject, null); }
set { _valuePropertyInfo.SetValue(_someObject, value, null); }
}
}
Edited With .NET 3.5 using LinFu
You may use LinFu instead of Castle. However, you would be using reflection anyway, both with Castle's and with Linfu's DynamicProxy, only hidden in the guts of the libraries instead of being exposed in your code. So if your requirement to avoid the use of reflection is out of performance concerns, you wouldn't really avoid it with this solution.
In that case I would personally choose Orsol's solution.
However: here's an example with LinFu's ducktyping.
public interface ISomeType {
object Value{get; set;}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeWrapperFactory
{
public static ISomeType CreateSomeTypeWrapper(object aSomeType)
{
return aSomeType.CreateDuck<ISomeType>();
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
foreach(var o in someTypes)
{
Console.WriteLine(SomeTypeWrapperFactory.CreateSomeTypeWrapper(o).Value);
}
Console.ReadLine();
}
}
Since you don't know the type of the SomeType's until runtime, I would not use mixins, but the visitor pattern (I know this doesn't answer the question on how to use mixins for this, but I just thought I'd throw in my 2 cents).
With .NET 4 using dynamic
See Bradley Grainger's post here on using c#4's dynamic keyword to implement the visitor pattern.
In your case, reading all the "Value" properties from your dictionary of SomeType's could work like this:
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeVisitor
{
public void VisitAll(object[] someTypes)
{
foreach(var o in someTypes) {
// this should be in a try-catch block
Console.WriteLine(((dynamic) o).Value);
}
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
var vis = new SomeTypeVisitor();
vis.VisitAll(someTypes);
}
}

Categories

Resources