C#: instantiating classes from XML - c#

What I have is a collection of classes that all implement the same interface but can be pretty wildly different under the hood. I want to have a config file control which of the classes go into the collection upon starting the program, taking something that looks like :
<class1 prop1="foo" prop2="bar"/>
and turning that into :
blah = new class1();
blah.prop1="foo";
blah.prop2="bar";
In a very generic way. The thing I don't know how to do is take the string prop1 in the config file and turn that into the actual property accessor in the code. Are there any meta-programming facilities in C# to allow that?

Reflection allows you to do that. You also may want to look at XML Serialization.
Type type = blah.GetType();
PropertyInfo prop = type.GetProperty("prop1");
prop.SetValue(blah, "foo", null);

It may be easier to serialise the classes to/from xml, you can then simply pass the XmlReader (which is reading your config file) to the deserializer and it will do the rest for you..
This is a pretty good article on serialization
Edit
One thing I would like to add, even though reflection is powerful, it requires you to know some stuff about the type, such as parameters etc.
Serializing to XML doesnt need any of that, and you can still have type safety by ensuring you write the fully qualified type name to the XML file, so the same type is automatically loaded.

I would also suggest Xml serialization as others have already mentioned. Here is a sample I threw together to demonstrate. Attributes are used to connect the names from the Xml to the actual property names and types in the data structure. Attributes also list out all the allowed types that can go into the Things collection. Everything in this collection must have a common base class. You said you have a common interface already -- but you may have to change that to an abstract base class because this code sample did not immediately work when Thing was an interface.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
string xml =
"<?xml version=\"1.0\"?>" +
"<config>" +
"<stuff>" +
" <class1 prop1=\"foo\" prop2=\"bar\"></class1>" +
" <class2 prop1=\"FOO\" prop2=\"BAR\" prop3=\"42\"></class2>" +
"</stuff>" +
"</config>";
StringReader sr = new StringReader(xml);
XmlSerializer xs = new XmlSerializer(typeof(ThingCollection));
ThingCollection tc = (ThingCollection)xs.Deserialize(sr);
foreach (Thing t in tc.Things)
{
Console.WriteLine(t.ToString());
}
}
}
public abstract class Thing
{
}
[XmlType(TypeName="class1")]
public class SomeThing : Thing
{
private string pn1;
private string pn2;
public SomeThing()
{
}
[XmlAttribute("prop1")]
public string PropertyNumber1
{
get { return pn1; }
set { pn1 = value; }
}
[XmlAttribute("prop2")]
public string AnotherProperty
{
get { return pn2; }
set { pn2 = value; }
}
}
[XmlType(TypeName="class2")]
public class SomeThingElse : SomeThing
{
private int answer;
public SomeThingElse()
{
}
[XmlAttribute("prop3")]
public int TheAnswer
{
get { return answer; }
set { answer =value; }
}
}
[XmlType(TypeName = "config")]
public class ThingCollection
{
private List<Thing> things;
public ThingCollection()
{
Things = new List<Thing>();
}
[XmlArray("stuff")]
[XmlArrayItem(typeof(SomeThing))]
[XmlArrayItem(typeof(SomeThingElse))]
public List<Thing> Things
{
get { return things; }
set { things = value; }
}
}
}

Reflection or XML-serialization is what you're looking for.
Using reflection you could look up the type using something like this
public IYourInterface GetClass(string className)
{
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in asm.GetTypes())
{
if (type.Name == className)
return Activator.CreateInstance(type) as IYourInterface;
}
}
return null;
}
Note that this will go through all assemblies. You might want to reduce it to only include the currently executing assembly.
For assigning property values you also use reflection. Something along the lines of
IYourInterface o = GetClass("class1");
o.GetType().GetProperty("prop1").SetValue(o, "foo", null);
While reflection might be the most flexible solution you should also take a look at XML-serialization in order to skip doing the heavy lifting yourself.

Plenty of metaprogramming facilities.
Specifically, you can get a reference to the assembly that holds these classes, then easily get the Type of a class from its name. See Assembly.GetType Method (String).
From there, you can instantiate the class using Activator or the constructor of the Type itself. See Activator.CreateInstance Method.
Once you have an instance, you can set properties by again using the Type object. See Type.GetProperty Method and/or Type.GetField Method along PropertyInfo.SetValue Method.

I recently did something very similar, I used an abstract factory. In fact, you can see the basic concept here:
Abstract Factory Design Pattern

I think you can utilize Dynamics here. Create ExpandoObject, it can be used either as Dictionary for setting properties from xml config.

Reflection is what you want. Reflection + TypeConverter. Don't have much more time to explain, but just google those, and you should be well on your way. Or you could just use the xml serializer, but then you have to adhere to a format, but works great.

Related

Best approach to instantiate object based on string

I'd like to discuss about the best approach (in C#) to instantiate an object based on an input string. Let me explain.
Let'say I have a base class:
public abstract class BaseCar
{
public asbtract int GetEngineID();
//Other stuff...
}
Then I have several implementations of this class, let's say:
public class SportCar : BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
public class OtherCar: BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
And so on...
What I'd like to do is to make a static CarFactory class which has a CreateCar method which accepts a string as a parameter and returns a BaseCar instance, depending on what string you give. The string would be a name of a child class.
For example, if I call CarFactory.CreateCar('SportCar') it should return a SportCar instance.
I know I could use a simple switch statement to check which car has been requested and create a new instance based on that but I don't like this approach for two reasons:
I plan to have a lot of child classes, hard-coding every case wouldn't be too easy to mantain
I plan to implement an inizialization procedure to also give some initial values to the objects I create (using Reflection), so mixing hard-coding and reflection doesn't seem to be a good idea for me.
What I was thinking about is to use the Assembly.CreateInstance from System.Reflection to create an instance of the specified class but since this is the first time I approach this problem, I don't know if there are better ways to do that. Is this a valid approach ?
Considering the input string will come from an XML file, is there a simplier method ? Maybe my issue is already handled in some .NET Assembly which I'm missing.
Here is what I came up with. A generic factory class that automatically registers all types that are a subclass of the given type, and allows you to instantiate them via their name. This is somewhat related to the approach shown in the Java SO question linked by #Achilles in the comments, only that there is no initialisation function associated with the type.
There is no need to maintain an enum/switch combination of all types. It should also be somewhat easily extendable to handle your proposed reflection based initialisation.
static class StringFactory<T> where T : class
{
static private Dictionary<string, Type> s_dKnownTypes = new Dictionary<string, Type>();
static StringFactory()
{
RegisterAll();
}
static private void RegisterAll()
{
var baseType = typeof(T);
foreach (var domainAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in domainAssembly.GetTypes()
.Where(t => t.IsSubclassOf(baseType)))
{
s_dKnownTypes.Add(type.Name, type);
}
}
}
static public T Create(string _sTypeName)
{
Type knownType;
if (s_dKnownTypes.TryGetValue(_sTypeName, out knownType))
{
return (T)Activator.CreateInstance(knownType);
}
throw new KeyNotFoundException();
}
}
Assuming the classes of your question exist, you would instantiate a specific car like this:
var car = StringFactory<BaseCar>.Create("SportsCar");
DoSomethingWith(car.EngineID());
Since your question was for a discussion about the best approaches, please consider this only one of them. I have not used this in a production environment, and it is entirely possible that it is the wrong approach to your specific situation. It works well enough to show the general principle, however, and should provide a starting point for further discussion.

Automating an object repository for a game

Hello guys i am having trouble designing an object repository for a game:
class ObjectRepository
{
private readonly LevelType _levelType;
private readonly BaseObject[] _darkForestObjects = new BaseObject[]
{ new DarkForestTreeA(), new DarkForestTreeB(), new DarkForestTreeC() };
private readonly BaseObject[] _lightForestObjects = new BaseObject[]
{ new LightForestTreeA(), new LightForestTreeB(), new LightForestTreeC() };
public ObjectRepository(LevelType lt)
{
_levelType = lt;
}
public BaseObject GetObject(int obj)
{
if (obj < 0 || obj > _darkForestObjects.Length)
{
Debug.LogError("Object does not exist.");
return null;
}
switch (_levelType)
{
case LevelType.DarkForest:
return _darkForestObjects[obj];
case LevelType.LightForest:
return _lightForestObjects[obj];
}
return null;
}
}
public enum LevelType
{
DarkForest = 0,
LightForest = 1,
}
I am searching for a way of automating this class.By automating it i mean that i don't want every time i create a new object deriving from BaseObject to come inside the Repository class and modify arrays.It just doesn't seem natural.Can anybody point me out a suggestion for automation?
I'll take a gander at this, so please let me know if I'm assuming things wrong.
You'll need:
A repository that'll hold your BaseObject-derived instances;
Said repository must be accessible by the BaseObject class;
Whenever a BaseObject is created, it adds itself to the repository.
Now, I've noticed that you hold instances for both dark and light versions of your objects. So I'd additionally suggest a holder class for both light and dark versions of a given 'object'. Like this:
class CompoundObject
{
public BaseObject LightVersion;
public BaseObject DarkVersion;
}
Your repository then hold CompoundObject-derived objects, and instead of BaseObject objects adding themselves at creation time, CompoundObject objects would do it.
Now about Array manipulations, you may be right; it can be somewhat clunky. I'd suggest the adoption of List<CompoundObject> instead of CompoundObject[]. A generic List offer very handy methods like Add and Remove that can streamline your collection manipulation.
If I were you, I would opt for a more generic solution using interfaces.
Considering your example, I assume that you have multiple level types which have their own specific TreeA, TreeB and TreeC implementations.
If I understood right, I would rather use interface for each tree type. Example for TreeA :
public interface ITreeA
{
// any common public members here
}
public class DarkForestTreeA : ITreeA, BaseObject
{
...
}
public class LightForestTreeA : ITreeA, BaseObject
{
...
}
This way, you can ask your repository to provide the ITreeA implementation specific to the level type. Something like :
public T GetObject<T>() // where T could be ITreeA, ITreeB...
{
...
}
So you could call myRepo.GetObject() and get a DarkForestTreeA object if level type is DarkForest for example.
To have this behavior "automated", you could declare all the specific implementations of DarkForest in a unique namespace and then use reflexion to find the class of the namespace that implements ITreeA for example. This may not be very efficient in terms of performance but it gives you great flexibility as you will just have to add new classes in your namespace to have them available from the repository. However, it can also bring other problems (for example, what would happen if you have two classes implementing ITreeA in the same namespace ?).
See Getting all types in a namespace via reflection and Getting all types that implement an interface with C# 3.0 for implementation details.
I have to admit it isn't the simplest solution.
You could consider simpler thing like defining a dictionary for object type (treeA, treeB) and then define a dictionary for each level type mapping the object type to its concrete implementation.
For example :
public enum ObjectType
{
TreeA,
TreeB,
TreeC,
}
Dictionary<ObjectType, Type> DarkForestObjectTypes = new Dictionary<ObjectType, Type>()
{
{ ObjectType.TreeA, typeof(DarkForestTreeA) },
{ ObjectType.TreeB, typeof(DarkForestTreeB) }
...
}
I won't go into more details as this answer looks a bit messy but hopefully it will give you ideas to go on with.

How to Shim long external dependency with ConcurrentDictionary (C#) via Microsoft Fakes?

In code I need to test was found such external dependency:
var something = GConfig.SConfig[Type.ServiceType1].Names;
Code of this part is like this:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Class
{
public sealed class GConfig
{
public ConcurrentDictionary<Type, GConfigIt> SConfig { get; set; }
public GConfig()
{
SConfig = new ConcurrentDictionary<Type, GConfigIt>();
throw new InvalidOperationException("Error");
}
}
public enum Type
{
ServiceType1,
ServiceType2
}
public class GConfigIt
{
public List<string> Names { get; set; }
public GConfigIt()
{
Names = new List<string>();
}
}
}
I need to shim that dependency, but on my own I can't find full solution, only partly:
For GConfigIt (and shimming Names): Fakes.ShimGConfigIt.AllInstances.NamesGet
For shimming SConfig: Fakes.ShimGConfig.AllInstances.SConfigGet
But I can't find connection, how to shim it fully.
P.S. I'm only a tester and can't change existing code. For making a change I need to convince developers to do it (i.e. extra interface for GConfig), but they must sure that it's not a change just for "easy testing" or "testing for testing" and they really need to do it.
Okay, so you are actually on the right track. You begin with Fakes.ShimGConfig.AllInstances.SConfigGet, and once that works, you need to shim the dictionary.
Probably something like Fakes.ShimConcurrentDictionary.AllInstances.ItemGetType which you can make return whatever GConfigIt you want, probably a stub.
You can either set the property of said stub or do what you were doing before for names.
I'm assuming the concurrent dictionary can be shimmed; If not, you still aren't stuck. Simply shim your SConfigGet to return a stub of SConfigGet, into which you can enter valid values. This might even be better than the other way, since you assume less about the implementation.

Find out whether property setter is called in DeSerialization process

Is there a way to find out whether an object property is called as part of the DeSerialization process (e.g. by the XmlSerializationReaderXXX).
Background: A typical scenario is to disable events and complex operations in that case, until the initialization is complete.
One approach I have found, is to "interpret" the stack and look up whether the call is triggered by XmlSerializationReaderXXX, which is not so elegant IMHO. Is there anything better?
public SomeClass SomeProperty
{
get { ..... }
set
{
this._somePropertyValue = value;
this.DoSomeMoreStuff(); // Do not do this during DeSerialization
}
}
-- Update --
As Salvatore has mentioned, somehow similar to How do you find out when you've been loaded via XML Serialization?
I have a possible solution.
public class xxx
{
private int myValue;
[XmlElement("MyProperty")]
public int MyPropertyForSerialization
{
get { return this.myValue; }
set
{
Console.WriteLine("DESERIALIZED");
this.myValue = value;
}
}
[XmlIgnore]
public int MyProperty
{
get { return this.myValue; }
set
{
Console.WriteLine("NORMAL");
this.myValue = value;
}
}
}
class Program
{
static void Main(string[] args)
{
xxx instance = new xxx();
instance.MyProperty = 100; // This should print "NORMAL"
// We serialize
var serializer = new XmlSerializer(typeof(xxx));
var memoryStream = new MemoryStream();
serializer.Serialize(memoryStream, instance);
// Let's print our XML so we understand what's going on.
memoryStream.Position = 0;
var reader = new StreamReader(memoryStream);
Console.WriteLine(reader.ReadToEnd());
// Now we deserialize
memoryStream.Position = 0;
var deserialized = serializer.Deserialize(memoryStream) as xxx; // This should print DESERIALIZED
Console.ReadLine();
}
}
The trick is using the XmlIgnore, it will force the xml serializer to ignore our property, then we use XmlElement to rename the property for serialization with the name of the property we want.
The problem with this technique is that you have to expose a public property for serialization, and is in some way bad because it can virtually be called by everyone.
It will not work if the member is private, unfortunally.
It works, is not totally clean, but is thread safe and don't rely on any flag.
Another possibility is to use something like the Memento pattern.
Using the same trick you can add a property called for example Memento that returns another object that contains properties suitable only for serialization, it can makes things a little cleaner.
Did you think instead of changing approach and using DataContractSerializer? It is much more powerful and produces pure XML. It supports the OnDeserializationCallback mechanism.
Since you got a pretty complex scenario you might want to consider creating a "data core" class which will be actually serialized/deserialized using simple direct way. Then your complex object is constructed from that object and you fire all events/operations as normal. It will make sequence of deserialize -> fire events/operations more explicit and easier to understand.
There's an OnDeserializingAttribute/OnDeserializedAttribute attributes pair. You can set isDeserializing flag while object is being deserialized. I don't know if they play well with XML serialization, though.
For XML Serialization solution could be implementing IXmlSerializable and embedding such logic into the ReadXml()/WriteXml() method
To have finer control of the deserialization process you could implement IXmlSerializable interface for SomeClass - in ReadXML you can then for example have some field set a flag that you are in deserialization... this flag can then be checked in the respective methods... and on completion it needs to be reset.
Another option (though not for XML IIRC) is to implement the above via OnDeserializingAttribute and OnDeserializedAttribute .
I misunderstood the question at first, but you want to ask from within setter if you are called during deserialization. To do that, use a static flag:
[serializable]
class SomeClass
{
public static IsSerializing = false;
SomeProperty
{
set
{
if(IsSerializing) DoYouStuff();
}
}
}
and then set the flag just before the serialization:
try
{
SomeClass.IsSerializing = true;
deserializedClass = (SomeClass)serializer.Deserialize(reader);
}
finaly
{
SomeClass.IsSerializing = false; //make absolutely sure you set it back to false
}
Note that same approach can work even if you deserialize a class that contains a member of your class...
Set a breakpoint on the property, and run in debug mode. It will break at the point of access for the getter/setter that you set the breakpoint on.

How to copy data from different classes by matching field or property names

I am looking to find a way to take two objects that have identical properties and make a call to copy the property values from one object into the other. The the example below assume I have an instance of A and I want to use the data of that instance to hydrate a new instance or C (to keep things terse I used fields instead of properties in the example below)
public class A : B
{
public string prop1;
public int prop2;
}
public class B
{
public byte propX;
public float propY;
}
public class C
{
public byte propX;
public float propY;
public string prop1;
public int prop2;
}
public class Merger
{
public static object Merge(object copyFrom, object copyTo)
{
//do some work
//maybe <T> generically refactor?
}
}
The merger class is just a psuedo-example, doing this through generics would be optimal but the first thing I question is whether such a capability already exists. I could imagine using reflection to do this myself but just wanted to toss it out for better ideas first.
Real world context: This is actually an MVVM related issue as I am trying to use disparate classes coming back from EF to populate a ViewModel instance.
Check out tools and libraries like AutoMapper - those would handle cases like this with ease - and much more! No need to re-invent the wheel - just use the tool! :-)
You would basically define a map between classes A and C like this:
Mapper.CreateMap<A, C>();
and then later on, you can have AutoMapper do the mapping, based on that map, from an instance of A into an instance of C, something like this:
C yourC = Mapper.Map<A, C>(instanceOfA);
AutoMapper does a default mapping based on property names (and types), but you can extend and influence it in a great many ways to include mappings from one property to another, even if the names (or types) don't match 100%. It's quite flexible and well established - definitely worth a serious look!
using System;
using System.Linq;
using System.Reflection;
public class Merger
{
public static TTarget Merge<TTarget>(object copyFrom) where TTarget : new()
{
var flags = BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic;
var targetDic = typeof(TTarget).GetFields(flags)
.ToDictionary(f => f.Name);
var ret = new TTarget();
foreach (var f in copyFrom.GetType().GetFields(flags))
{
if (targetDic.ContainsKey(f.Name))
targetDic[f.Name].SetValue(ret, f.GetValue(copyFrom));
else
throw new InvalidOperationException(string.Format(
"The field “{0}” has no corresponding field in the type “{1}”.",
f.Name, typeof(TTarget).FullName));
}
return ret;
}
}
class Program
{
static void Main(string[] args)
{
var a = new A { prop1 = "one", prop2 = 2, propX = 127, propY = 0.47f };
var c = Merger.Merge<C>(a);
Console.WriteLine(c.prop1); // prints one
Console.WriteLine(c.prop2); // prints 2
Console.WriteLine(c.propX); // prints 127
Console.WriteLine(c.propY); // prints 0.47
}
}
This isn't the best solution by far, but based on the object graph you've provided, you could probably accomplish this by XML serializing the first object, and XML deserializing the XML stream into the second object.
Your proposed Merger method could possibly look like this:
public class Merger
{
public static object Merge(object copyFrom, object copyTo)
{
var xmlContent = MyXMLSerializationMethod(copyFrom);
MyXMLDeserializationMethod(xmlContent, typeof(copyTo), out copyTo);
return copyTo;
}
}
Good post about using AutoMapper to solve this problem in the context of MVVM and MVC
http://www.bengtbe.com/blog/post/2009/04/14/Using-AutoMapper-to-map-view-models-in-ASPNET-MVC.aspx

Categories

Resources