How can I get a collection's parent object?

2.6k views Asked by At

In C#, if I have an object that has a collection, is it possible to retrieve the object that contains the collection?

Here is an example:

public class TestObject
{
    public string name { get; set; }
    public TestObjectCollection testObjects{ get; set; } 
}

The TestObjectCollection collection inherits from CollectionBase and is a collection of TestObjects.

Here is an example implementation:

  • A TestObject is created with a name of "Test1"
  • The TestObject with the name of "Test1" has a TestObjectCollection with a TestObject with a name of "Test2"

If I have the TestObject with the name of "Test2", how can I get the TestObject with the name of "Test1"

Thanks

4

There are 4 answers

4
Yogesh On BEST ANSWER

The only way to do this is to keep a reference to the parent in the child object. You can do this while creating the child object:

this.testObjects = new TestObjectCollection(this);

Then in TestObjectCollection's constructor:

public TestObject ParentObject { get; set; }

public TestObjectCollection(TestObject parent)
{
    ParentObject = parent;
    ...
}
0
mad MIckO On

Maybe you can do it like this :

using System;
using System.Collections.Generic;

public class TestObject
{
    private TestObjectCollection _testObjects;

    public string name { get; set; }
    public TestObjectCollection parentCollection { get; set; }
    public TestObjectCollection testObjects 
    { 
        get
        {
            return _testObjects;
        }
        set 
        {
            _testObjects = value;
            _testObjects.parent = this;
        }
    }
}

public class TestObjectCollection
{
    private List<TestObject> _testObjects;

    public TestObject parent { get; set; }

    public TestObjectCollection()
    {
        _testObjects = new List<TestObject>();
    }

    public void Add(TestObject testObject)
    {
        testObject.parentCollection = this;
        _testObjects.Add(testObject);
    }

    public TestObject this[int i] {
        get {
            return _testObjects[i];
        }
    }
}


public class Test
{
    public static void Main()
    {
        // your code goes here
        TestObject test1 = new TestObject();

        TestObject test2 = new TestObject();

        var collection = new TestObjectCollection();
        collection.Add(test2);
        test1.testObjects = collection;

        if (test2.parentCollection.parent == test1)
        {
            Console.WriteLine("Done");
        }
        else
        {
            Console.WriteLine("Fail");
        }
    }
}

I used List as an example.

0
Edmund Schweppe On

Unless you explicitly code that parent-child relationship (as in Yogesh's answer), there's no way to find "the" parent - in large part because there can be more than one such parent:

public class TestObject
{
    public string name { get; set; }
    public TestObjectCollection testObjects{ get; set; } 
}
public class TestObjectCollection : CollectionBase
{
    public void Add(TestObject to)
    {
        this.List.Add(to);
    }
}
void Main()
{
    TestObjectCollection children = new TestObjectCollection();
    TestObject child = new TestObject { name = "child" };
    children.Add(child);

    TestObject parent = new TestObject { name = "parent", testObjects = children }; 
    TestObject otherParent = new TestObject { name = "otherParent", testObjects = children };   
    TestObject stepParent = new TestObject { name = "stepParent", testObjects = children }; 
    TestObject inLocoParentis = new TestObject { name = "inLocoParentis", testObjects = children };
    // and we can keep going on and on and on ...   
}
2
Ryan Mann On

If you don't want to pass referrences in the constructors, you can use a static dictionary to keep track of TestObject instances and have the TestObjectCollection look up it's parent from that static dictionary in a lazy loading fashion.

For example

public class TestObject
{
    /// <summary>
    /// Keep a list of all the instances of TestObject's that are created.
    /// </summary>
    internal static Dictionary<Guid, TestObject> _collections = new Dictionary<Guid, TestObject>();

    /// <summary>
    /// An ID to uniquely identify an instance of a TestObject
    /// </summary>
    public Guid ID { get; private set; }

    /// <summary>
    /// A reference to the collection which will be set in the constructor
    /// </summary>
    public TestObjectCollection TestObjects { get; private set; }

    public TestObject()
    {
        //generate the unique id
        this.ID = Guid.NewGuid();
        this.TestObjects = new TestObjectCollection();
        //add this testobject to the List of test objects.
        _collections.Add(this.ID, this);
    }

    /// <summary>
    /// Destructor, kill the TestObject from the list of TestObject's.
    /// </summary>
    ~TestObject()
    {
        if (_collections.ContainsKey(this.ID))
        {
            _collections.Remove(this.ID);
        }
    }
}

public class TestObjectCollection : IEnumerable<TestObject>
{
    private List<TestObject> _testObjects = new List<TestObject>();

    public Guid ID { get; private set; }

    public TestObject this[int i]
    {
        get
        {
            return _testObjects[i];
        }
    }

    private TestObject _Parent = null;
    public TestObject Parent
    {
        get
        {
            if (_Parent == null)
            {
                _Parent = TestObject._collections.Values.Where(p => p.TestObjects.ID == this.ID).FirstOrDefault();
            }
            return _Parent;
        }
    }

    public TestObjectCollection()
    {
        this.ID = Guid.NewGuid();
    }

    public void Add(TestObject newObject)
    {
        if (newObject != null)
            _testObjects.Add(newObject);
    }

    public IEnumerator<TestObject> GetEnumerator()
    {
        return _testObjects.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _testObjects.GetEnumerator();
    }
}

Testing...

class Program
{
    static void Main(string[] args)
    {
        TestObject tObject = new TestObject();
        Console.WriteLine("TestObject ID: " + tObject.ID);
        Console.WriteLine("TestObject TestObjectCollection ID: " + tObject.TestObjects.ID);
        Console.WriteLine("TestObject TestObjectCollection Parent ID: " + tObject.TestObjects.Parent.ID);
        Console.WriteLine("Press any key...");

        Console.ReadKey(true);
    }
}

So what this does is in the constructor of TestObject it give's itself a GUID ID. Then it creates an Instace of TestObjectCollection.

In the Constructor of TestObjectCollection it give's itself a GUID ID.

Back in the constructor of TestObject it Set's TestObjects to the collection it just created, then adds a referrence to itself to the Dictionary of TestObjects which is static. It uses TestObject's ID as the Key for said Dictionary.

Then in TestObjectCollection it get's the parent collection by looking it up in that Static Dictionary using a property that doesn't set itself till it's called (as you can't determine it in the constructor because the TestObject constructor hasn't added the referrence yet).

    private TestObject _Parent = null;
    public TestObject Parent
    {
        get
        {
            if (_Parent == null)
            {
                _Parent = TestObject._collections.Values.Where(p => p.TestObjects.ID == this.ID).FirstOrDefault();
            }
            return _Parent;
        }
    }