Tag Archives: Recursion

Dynamically copy a class from one instance to another using reflection

Occasionally, you find that you want to copy a class to another instance of itself. There are various reason, but typically the code can result in a `CopyTo()` function, with a long list of properties to be copied across. There’s nothing wrong with that and, performance-wise, it’s probably faster than what I’m suggesting in this post.

Here’s a generic method that will copy the class for you:

        private static void CopyClass<T>(T copyFrom, T copyTo)
        {
            if (copyFrom == null || copyTo == null)
                throw new Exception("Must not specify null parameters");

            var properties = copyFrom.GetType().GetProperties();

            foreach (var p in properties.Where(prop => prop.CanRead && prop.CanWrite))
            {
                object copyValue = p.GetValue(copyFrom);
                p.SetValue(copyTo, copyValue);
            }
        }

Nothing too onerous if you’ve ever seen reflection, but let’s quickly run through it. The first thing it does is ensure that both to destination and source are provided, then it gets a list of properties that can be read and written to, and copies the value across.

Obviously, this won’t include any private properties.

Here’s some test / example code for it. First, the class to copy:

    class TestClass
    {
        public string teststring { get; set; }

        public string mynextstring { get; set; }

        public void test()
        {

        }

        public int get1 { get { return 1; } }

        //public TestClass2 testClass2 { get; set; }
    }

And then tha calling code:

            TestClass tc = new TestClass()
            {
                //testClass2 = new TestClass2(),
                teststring = "test2123",
                mynextstring = "31"

            };

            var t = new TestClass();
            CopyClass<TestClass>(tc, t);
            Console.WriteLine(t.teststring);
            Console.WriteLine(t.mynextstring);
            //Console.WriteLine(t.testClass2.teststring);

            Console.ReadLine();

Okay, so that works; however, you’ll notice that I’ve included and commented out an external class reference. If you include this, then it will copy the class reference (not the class). What if we want to use this to copy child classes?

Actually, it’s not too complicated:

        private static void CopyClass<T>(T copyFrom, T copyTo, bool copyChildren)
        {
            if (copyFrom == null || copyTo == null)
                throw new Exception("Must not specify null parameters");

            var properties = copyFrom.GetType().GetProperties();

            foreach (var p in properties.Where(prop => prop.CanRead && prop.CanWrite))
            {
                if (p.PropertyType.IsClass && p.PropertyType != typeof(string))
                {
                    if (!copyChildren) continue;

                    var destinationClass = Activator.CreateInstance(p.PropertyType);
                    object copyValue = p.GetValue(copyFrom);

                    CopyClass(copyValue, destinationClass, copyChildren);

                    p.SetValue(copyTo, destinationClass);                  
                }
                else
                {
                    object copyValue = p.GetValue(copyFrom);
                    p.SetValue(copyTo, copyValue);
                }
            }
        }

There’s a couple of things to note here: firstly, we need to check if the value is a class, but exclude strings as a special case (I couldn’t find a neater way of doing this); secondly, create the destination class using reflection and cache the source value. Finally, we just recursively call the function, using generic type inference in order to supply the type (which we don’t have as a generic at this point).

If you now just uncomment out the references to TestClass2 it should recursively copy the class.

I have to be honest and say that I’m not too happy with the check for a string type, but other than that, this is quite a neat little way to copy a class.

Reading an XML Document using XmlDocument

I recently saw a question on SO relating to this, and pretty much every answer was: “Use LINQ To Xml”. Which is good advice. If you don’t want to do that (for whatever reason), then you may decide to use an approach such as the following.

Disclaimer

I am not stating that this is the best was to accomplish this, merely that it is a way. I am also not asserting that any of the books mentioned exist in the libraries they are listed under.

The Code

Declare the XML string here. Note; if you intend to read this from a file then just call Xml.Load() later on, instead of LoadXml.

        static string xmlDoc =
            @"<RootNode>
                <Library Name='Manchester'>
                    <Book>
                        <Title>Fly Fishing</Title>
                        <Author>J. R. Hartley</Author>
                        <Floor>1</Floor>
                    </Book>
                    <Book>
                        <Title>To Kill A Mockingbird</Title>
                        <Author>Harper Lee</Author>
                        <Floor>3</Floor>
                    </Book>
                </Library>
                <Library Name='London'>
                    <Book>
                        <Title>1984</Title>
                        <Author>George Orwell</Author>
                        <Floor>2</Floor>
                    </Book>
                </Library>
            </RootNode>";

Load the document:

            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmlDoc);
            XmlNodeList nodes = xml.ChildNodes;
            ReadXmlNodes(nodes);

            Console.ReadLine();

And traverse it:

        /// <summary>
        /// Traverse the XML node and print the values
        /// </summary>
        /// <param name="nodes"></param>
        private static void ReadXmlNodes(XmlNodeList nodes)
        {
            foreach (XmlNode node in nodes)
            {
                // Omit #text nodes
                if (node.NodeType != XmlNodeType.Text)
                {
                    Console.WriteLine(node.Name);
                }

                // Check if there are any attributes and, if so, print them now
                if (node.Attributes != null)
                {
                    PrintAttributes(node);
                }

                // If the node is a parent then recurively call the function
                if (node.HasChildNodes)
                {
                    ReadXmlNodes(node.ChildNodes);
                }
                // Otherwise just print the value
                else
                {
                    Console.WriteLine("Node Value: {0}", node.Value);
                }
            }

        }

        /// <summary>
        /// Print all the attributes for a node
        /// </summary>
        /// <param name="node"></param>
        private static void PrintAttributes(XmlNode node)
        {
            foreach (XmlAttribute att in node.Attributes)
            {
                Console.WriteLine("Attribute: {0}", att.Value);
            }
        }
    }

Detecting Recursion – JSON.Net Stack Overflow

Trying to save the game class of a game that I’m working on, I got a Stack Overflow error. I’m using MVVMCross, and my code looked like this:

        public void Save()
        {
            var jsonConv = Mvx.Resolve<IMvxJsonConverter>();
            string text = jsonConv.SerializeObject(this);
            FileHelper.SaveGameFile(text);
        }

The problem was that I got this error:

An unhandled exception of type ‘System.StackOverflowException’ occurred in mscorlib.dll

stackoverflow

I had a pretty good idea why. My game features a large population of “people”. Some of these people relate to each other; for example, they are parents, children, employers, etc. My guess was that I’d somehow messed up the creation routine and ended up with a recursive reference. (As it happened, far from messing it up, I hadn’t considered that a spouse relationship is recursive by definition!)

The Problem

The problem was that I had a starting population of 10,000 people. There are other ways to solve this: representing the reference between the classes as some kind of index, debugging the creation code, etc… However, I wanted to see if I could write a program to detect this.

My test program looks like this:

    class MyData
    {
        public MyData recursiveRef { get; set; }
        public string test { get;set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<MyData> data = new List<MyData>()
            {
                new MyData() {recursiveRef = null, test="non-recursive" },
                new MyData() {recursiveRef = null, test="recursive ref 1" },
                new MyData() {recursiveRef = null, test="recursive ref 2" },
                new MyData() {recursiveRef = null, test="recursive ref 3" },
                new MyData() {recursiveRef = null, test="recursive ref back to 1" }
            };
            data[1].recursiveRef = data[2];
            data[2].recursiveRef = data[3];
            data[3].recursiveRef = data[4];
            data[4].recursiveRef = data[1];

            SerialiseData(data);

            Console.ReadLine();
        }

        private static void SerialiseData(List<MyData> data)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings()
            {
                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
            };

            var ser = JsonConvert.SerializeObject(data, Formatting.None, settings);
            Console.Write(ser);
        }

Quickly running this will error with a stack overflow (to clarify, slowly running it will result in the same error!).

Detection Routine

Here’s the functions that I wrote to detect recursion:

        /// Itterate the list and call method CheckElement to analyse each element
        private static bool DetectRecursion<T>(IEnumerable<T> data)
        {
            Type typeT = typeof(T);

            foreach (T element in data)
            {
                if (CheckElement<T>(typeT, element, typeT, element))
                {
                    Console.WriteLine("Recursion found - exiting");
                    Console.ReadLine();
                    return true;
                }
            }

            return false;
        }

        private static List<object> recursionChain;

        /// Method recursively traverses the object to determine if there are any recursove references
        private static bool CheckElement<T>(Type baseType, T baseElement, Type checkType, object checkElement)
        {
            PropertyInfo[] piArr = checkType.GetProperties();
            foreach (PropertyInfo pi in piArr)
            {
                Console.WriteLine("Checking {0}, type {1}", pi.Name, pi.PropertyType);
                if (pi.PropertyType != baseType)
                    continue;

                var val = pi.GetValue(checkElement);
                if (val == null) continue;

                Console.WriteLine("Value for {0} is {1}", pi.Name, val.ToString());

                Type piType = val.GetType();

                if (piType == baseType && val.Equals(baseElement))
                {
                    return true;
                }

                if (CheckRecursionChain(val, piType)) return true;

                if (CheckElement<T>(baseType, baseElement, piType, val))
                {
                    Console.WriteLine("Successfully found recursive element {0}, {1}", piType.ToString(), val.ToString());
                    return true;
                }
            }

            return false;
        }

        /// Check the static recursion chain for a match
        private static bool CheckRecursionChain(object val, Type piType)
        {            
            if (Program.recursionChain != null && Program.recursionChain.Contains(val))
            {
                Console.WriteLine("Successfully found recursive element {0}, {1}", piType.ToString(), val.ToString());
                return true;
            }

            if (Program.recursionChain == null)
                Program.recursionChain = new List<object>();

            Program.recursionChain.Add(val);
            
            return false;
        }

This is, admittedly, not a simple or short piece of code; having said that, it doesn’t do anything complex, once you’re happy with the reflection, the rest is just a recursive tree.

To use this, simply call `DetectRecursion` in the above test program before calling serialize (or instead of).

...
DetectRecursion(data);

//SerialiseData(data);

...