Exchanging a referenced object for another

Started by
10 comments, last by captain_crunch 15 years, 8 months ago
Hi all, I have a list collection that is referenced from many other objects. Now I want to exchange the list collection for a different one. The old one is deleted. The client objects should carry on as if nothing had happened. Is there a software pattern that will allow me to do this, and have all the referencing objects point to the new collection, or in effect work on the new collection from now on, without having to reset all the references one at a time? I code in C# but I would think this is a general issue...
Advertisement
You have to use an additional level of indirection. Have all your objects reference an object that itself references the container. When you replace the container with another, change the single reference to that container, and all the other objects will use the new one.
In this case I'm merging two lists. Only one list will be kept. If I use your approach and I have an in-between object for each list to start with, I will then end up with two in-between objects referencing the same list.
I suppose this is an acceptable solution...
I think the solution you proposed is the right one. I will create an encapsulating class and use that instead of the list.

I have but one more question, if I may...

In the new encapsulating class, do you think it matters whether I:

Expose the list as a public member and perform operations on it directly

Or

Implement all used methods, including the indexing operator, and pass the calls through to the private list member?

Ummm...
Why not do something like this.

void MergeLists(List<object> listA, List<object> listB){      listA.AddRange(listB);      listB = listA;}


At the end, listA and listB should reference the same object. The old listB goes to the garbage collector and everyone referencing the list should still be happy.
I'm pretty sure that wouldn't work. Setting the parameter to a new value doesn't affect the caller.

However, this might work:

void MergeLists(ref List<object> listA, ref List<object> listB)
{
listA.AddRange(listB);
listB = listA;
}


Using the ref keyword should make the change affect the caller. But it doesn't solve my problem, because I have many references to each list, and using this method will only affect the one caller, not the other references.
You don't. Not really, at least, since you can't really "store" references to references in C# AFAIK.

You can try this:
class MyList{    public List<object> List { get; set; }}class ClientA{    public MyList Foo { get; set; }    // ...}class ClientB{    public MyList Foo { get; set; }    // ...}

// Initialisation somewhereMyList foo;foo.List = new List<object>();ClientA clientA = new ClientA();ClientB clientB = new ClientB();clientA.Foo = foo;clientB.Foo = foo;// Somewhere elsefoo.List = someOtherList;

Since all your clients hold a reference to the single MyList class, you can freely change the MyList.List member, and all your clients will then use the new list.

It's not an ideal solution, and there's probably a better way to do it. But it'd work.
NextWar: The Quest for Earth available now for Windows Phone 7.
Quote:Original post by Sc4Freak
Since all your clients hold a reference to the single MyList class, you can freely change the MyList.List member, and all your clients will then use the new list.


Yeah, I thought I had made it, but the situation seems to be a bit more complicated. See, I want to merge the two lists. I have updated your example to show what I mean:

// Two containersMyList fooA;MyList fooB;// Two listsfooA.List = new List<object>();fooB.List = new List<object>();// Two clients, one for each containerClientA clientA = new ClientA();ClientB clientB = new ClientB();clientA.Foo = fooA;clientB.Foo = fooB;// Somewhere else// Merge the lists:fooA.List = fooA.List.Append(fooB.List);// set container B to point at the merged list:fooB.List = fooA.List


Both containers now point to one list.
The problem comes when I need to merge the list again. To do this, I now have to change the List property on three containers, instead of two, to point to the same list. And the next time four, and so on. I would have to keep track of every container that has ever existed, forever, because I wouldn't know if any clients were still referencing it.

So I have replaced the problem of keeping track of the clients with keeping track of the new container objects.
I'm not too good with C#, i mostly code in c++, but maybe this will work.

class TheList
{
list<Object> m_list;
list<Client> m_clients;

AddRefToClient(Client& c)
{
c.m_listRef = this;
m_clients.push_back(c);
}

//implement a remove reference from client

//1. overload a += operator or implement merge function that takes in a TheList object
//2. inside this function iterate through passed in objects m_clients
//3. update each client as you iterate to to point to this list
// using the AddRefToClient function
};

class Client
{
friend class TheList; //not sure if this is available in c#, i think c#
//uses the internal keyword instead

list<Object>& m_listRef; //not sure if & is needed in c#

//do not provide a way to set the m_listRef reference
//the only way to set this reference would by through the TheList class
//AddRefToClient function
};

The friend keyword may not work in c# but I think the internal keyword does something similar also its used differently. Essentially what it would do in c++ is let "TheList" class to access private variables in the client class without exposing them to the rest of the app.

In any case, if that doesn't work you can always make a setter function or property for the m_listRef variable. The only problem with doing this is that the m_listRef variable will be exposed to the rest of the app allowing it to be changed by classes other then TheList.
Yeah, registering the clients in some way might work... but I think I want a looser coupling still...

My newest idea is to not let the clients hold a reference to the lists at all. Instead, they will have an ID and call into a single map/dictionary that maps ID numbers to list references. In this way, I can update the map when lists are merged or switched about by changing the value part to point to the new list for the ID keys that are affected.

The downside to this approach is that the map could keep growing indefinitely as lists are merged, and more and more entries must be added.

This topic is closed to new replies.

Advertisement