Get all objects that inherit from another class?

I am making a system in my game where a modder will be to add a “Action” to the game with a Add method. I haven’t added the Add method in yet thought, because I have ran into a problem. Every “Action” is inside of an XML file with configurable settings. This works fine if I wasn’t allow modding, but since I have to do [XmlInclude(typeof(TYPEHERE))], it doesn’t work with modding. The reason I need these lines is because the XmlSerializer class doesn’t work without them because of the inheritance going on.

So basically, how would I do [XmlInclude(typeof(EveryChildOfActionClass))]

Here is my code, so you know what I mean:

[XmlInclude(typeof(Throw))]
    public class Action {
        [XmlAttribute("name")]
        public string name;

        public Action() { } //Blank constructor

        public Action(string name) {
            //Set up the action's settings
            this.name = name;
        }

        public string GetName() { //Returns name of the action
            return name;
        }
    }

This is what I mean. At the very top, you see XmlInclude, and then a specific type. Well, if I am allowing modder to create their own classes, I wont know every single type that is in the game. So how do I add multiple XmlInclude lines, and at the same time have them not be specifically typed. If I need to explain, please let me know.

Here is some more code:

public class Throw : Action {
        [XmlElement("throw_power")]
        public float throwPower;

        public Throw() { } //Blank constructor

        public Throw(string name, float throwPower) : base(name) {
            //Set up the action's settings
            this.name = name;
            this.throwPower = throwPower;
        }

        public float GetThrowPower() { //Returns name of the action
            return throwPower;
        }
    }

Notice that this is how an “Action” gets created. A class just inherits from the Action class. If modders create their own class, it will be impossible to know what it is called for the XmlInclude line.

[XmlRoot("action_pool")]
    public class ActionPool {
        [XmlArray("actions")]
        [XmlArrayItem("action")]
        public List<Action> actions = new List<Action>();

        public void AddDefaultActions() {
            actions.Add(new Throw("Throw", PlayerManager.Instance.settings.interactSettings.throwPower));
        }
    }

And this is what the XML file looks like:

<action_pool xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <actions>
    <action xsi:type="Throw" name="Throw">
      <throw_power>20</throw_power>
    </action>
  </actions>
</action_pool>

Bump… Please help out. I am soo stumped right now Lol.

Really your problem is that you need the xml serializer be able to recognize types that you yourself don’t even know yet, because they will be loaded in, in post.

OK, well I don’t know the XmlSerializer very well… If I’m using the .net library for my serialization (which it has many serializers, many of which don’t interoperate… ugh) I primarily use the System.Runtime.Serialization namespace, primarily the BinaryFormatter:

I like this namespace because it allows tons of tweaking of the serialization pipeline via custom formatters, and hooks like IDataContractSurrogate, IDeserializationCallback, ISerializationSurrogate, and ISurrogateSelector.

Anyways, by default these serializers can infer any class type when serializing or deserializing without having to do all this ‘XmlInclude’ nonsense. As long as the type is loaded into the Application Domain it can figure out what it is (this happens when you load up the dll’s that contain the custom scripts you allow modders to write).

So yeah, I’d probably suggest not using the XmlSerializer…

If you don’t like the binary format of the resulting data, you can write a custom formatter to support something else (.net only comes with binary, and soap a subset of xml). I recently wrote a json one, as well as one to support grfon (a format design by another user here on the forums). I can dig them up if you’re interested.

I’m using XmlSerializer for a reason. It does sooo much of the work for me. I wrote my own LoadXML function that will load an XML file if it exists, and if it doesn’t exist, then it will create an XML file that is properly made. Using Binary is also not what want at all for a list of every action. You will be able to view every action from the file.

There are also other files such as “PlayerSetting.xml” which contains data such as the player walk speed. And yes, I am letting players modify this. It fits the type of game I’m making.

So Binary files are just not what I want lol.

Thing is, there’s no way to tell XmlSerializer about these types at compile time, if you don’t know those types exist yet. Unless there’s some other way to inform it in post, but as far as I know it does not (I also don’t like the fact it doesn’t let you control what gets serialized or not, it only serializes public fields… ugh).

Here’s an implementation of IFormatter for XML:
http://www.codeproject.com/Articles/15639/XMLFormatter-provider-for-serialization

So actually I solved this problem by using generics. This isn’t the best way, but it definitely isn’t the worse by far. I am going to show you quite a lot of code so you can see what I’m doing. Basically, there is a ListAsXML method that will serialize OR deserialize an XML file to/from a list.

Here is the method:

//Serializes/Deserializes a list to/from an XML file
        public static List<ListType> ListAsXML<ListType>(List<ListType> list, bool serializing, string directory, string fileName, string rootName = null) {
            string path = directory + fileName; //Combines both paths
            CreateDirectory(directory); //Creates directory if it doesn't exist

            List<System.Type> types = new List<System.Type>();

            foreach(ListType obj in list) { //Loops through every item in the list
                System.Type type = obj.GetType();

                if(!types.Contains(type)) //If types list doesn't have the current object's type on it
                    types.Add(type); //Add current object's type to the list
            };

            XmlSerializer serializer; //Initialize serializer

            if(rootName == null) //If root name wasn't given
                serializer = new XmlSerializer(typeof(List<ListType>), null, types.ToArray(), null, null); //Create with default root name
            else
                serializer = new XmlSerializer(typeof(List<ListType>), null, types.ToArray(), new XmlRootAttribute(rootName), null); //Create with given root name

            /* Serilization */
            if(serializing) {
                using(FileStream stream = File.Open(path, FileMode.Create)) //Automatically closes the file after it's done being used
                    serializer.Serialize(stream, list); //Serializes data to the file

                return list;
            }
            /* Deserilization */
            else {
                if(File.Exists(path)) { //Makes sure XML file exists
                    using(FileStream stream = File.Open(path, FileMode.Open)) //Automatically closes the file after it's done being used
                        return (List<ListType>)serializer.Deserialize(stream); //Deserializes the data and returns it
                } else
                    return list;
            }
        }

See? It is quite a bit of code(not that bad though), and there is even a little more code that is being run, but it isn’t too important to be shown. Somehow, I got this to work from using Google, and my mind. This has been the biggest stump I have ever came across, but I have also learned quite a lot lol.

Thank you for trying to help though, I really do appreciate it. This final method is like a dream come true, because it gets rid of the need to say [XmlInclude()], which really is non-sense as you said ha ha.