So I'm working with code in which there are two object that contain each other, inside a list of which I do not know the contents of until runtime. I have a function that needs to convert the first object to a third object, but to do such I need to convert the second object aswell, however to do that I will need the convert the first, and here is the chicken and the egg problem.

Problem Example

namespace chicken // Also I like formatting my code like this, so don't judge me
{
    public class Object1 { // Object One and Two are of the same class
        public List<dynamic> contents = new List<dynamic>();

        public Object1() {}
        public Object1(List<dynamic> contents) {
            this.contents = contents;
        }
    }

    public class Object3 {
        public string name;
        public Object3 friend;
        public string pet;

        public Object3(List<dynamic> converted) {
            this.name = converted[0];
            this.friend = converted[1];
            this.pet = converted[2];
        }
    }

    public class Program {
        public static void Main(string[] args) {
            Object1 object1 = new Object1(); // Just to create the problem, they don't
            Object1 object2 = new Object1(); // get created like this in the actual code

            object1.contents = new List<dynamic> {
                "Steve Johnson", // This is example data, this order is supposed to be unknown
                object2,
                "Biscut",
            };

            object2.contents = new List<dynamic> {
                "Bob Smith",
                object1,
                "Tiny",
            };

            Object3 final = convert(object1); // Runs the conversion function
        }

        public static Object3 convert(Object1 obj) {
            List<dynamic> converted = new List<dynamic>(); // I need a sanitized list for Object3
            for (int i = 0; i < obj.contents.Count; i++) {
                if (obj.contents[i] is Object1) {
                    converted.Add(convert(obj.contents[i])); // Causes infinite loop due to chicken and egg problem
                    continue;
                } converted.Add(obj.contents[i]);
            }
            
            Object3 object3 = new Object3(converted); // Again the list order is unknown
            return object3;
        }
    }
}

I've tried using references, where there is a tunnel object and 'Object3' passes references to it's varibles to it, so I can semi construct Object3, put it in a cache, pass it to object 2 to convert it, then put in the values though the tunnel object containing the references. This got to complicated and I honestly don't know what to do without having an empty constuctor for Object 3.

2

There are 2 answers

0
StriplingWarrior On BEST ANSWER

The problem you're describing can be simplified down to this:

In the following code, how can we make it so Node a references b and b references a?

Node a, b;
a = new Node(new object[] { b });
b = new Node(new object[] { a });

public record Node(IEnumerable<object> Links);

You already hit on the solution: allow a Node to be constructed without all of its possible objects, so you can construct the Nodes first, and then insert them where they belong. It sounds like you don't want to give Node ("Object3") a default constructor, but the way you've implemented it at the moment, it should still be possible to add values after the fact, if you can add to its items list after its construction.

List<object> aList = new(), bList = new();
Node a = new Node(aList), b = new Node(bList);
aList.Add(b);
bList.Add(a);

If that will work for you, then the rest is just the details you've described:

using references, where there is a tunnel object and 'Object3' passes references to its variables to it, so I can semi construct Object3, put it in a cache, pass it to object 2 to convert it, then put in the values though the tunnel object containing the references.

It may be complicated, but that's pretty much what has to happen.

If, for some reason, you need your Object3 class structure to be immutable, so you cannot change its contents after its construction, then you're at an impasse: your requirements are clearly impossible. You're defining an object that must be constructed with all its dependencies, but its dependencies need it to be constructed before they can be constructed.

0
Enigmativity On

Here is a minimal representation of your code:

namespace chicken
{
    public class Program
    {
        public static void Main(string[] args)
        {
            List<dynamic> chicken1 = new List<dynamic> { "Steve Johnson", null, "Biscut", };
            List<dynamic> chicken2 = new List<dynamic> { "Bob Smith", chicken1, "Tiny", };
            chicken1[1] = chicken2;
            Convert(chicken1);
        }

        public static void Convert(List<dynamic> chicken)
        {
            foreach (dynamic inner in chicken)
            {
                if (inner is List<dynamic>)
                {
                    Convert(inner);
                }
            }
        }
    }
}

You've just created two dynamic lists that refer to each other and then you try to recursively navigate from one list to the other infinitely.

There is nothing about an egg is your scenario that causes your problem. And, there's very little to do with chickens either, as you really only have two dynamic lists.

I suspect you have a real-world example that may have a chicken versus egg problem, but you haven't translated it into your question.

The bottom-line for me is that there are very few good uses for the keyword dynamic. In 99% of cases it's just syntactic sugar for adding bugs in your code.