How to reference back and forth

Variable in a class has to know its parent

Page 1 of 1

9 Replies - 849 Views - Last Post: 21 June 2009 - 12:24 PM Rate Topic: -----

#1 SoftwareTester  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 11-August 08

How to reference back and forth

Posted 17 June 2009 - 12:06 AM

I have a class containing a list of elements that need to know to what object they belong. How do I do that
public class StockExchange
{
private List<TickerIndex> ListOfIndexes = null;
private string name="";
public StockExchange(string NameExchange)
{
ListOfIndexes = new List<TickerIndex>();
}
public bool Add(TickerIndex NewIndex)
{
bool bAdded = false;
if (NewIndex.StockExchange == null)
{ // This is what is all about : I want to be SURE a TickerIndex can only be added to ONE StockExchange and I also must know to WHAT StockExchange it has been added 
ListOfIndexes.Add(NewIndex);
NewIndex.StockExchange = this;
bAdded = true;
}
return bAdded;
}
}

public class TickerIndex
{
private StockExchange stockExchange = null; // Something REFERRING to a StockExchange but WHAT??

// Contains :
public StockExchange
{
get
{
return stockExchange;
}
set
{
if ((stockExchange == null) && (value != null))
{
stockExchange = value;
} 
}
}
} 



If there is a much better approach pls let me know

Is This A Good Question/Topic? 0
  • +

Replies To: How to reference back and forth

#2 eburger  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 16-June 09

Re: How to reference back and forth

Posted 17 June 2009 - 12:25 AM

Quote

I have a class containing a list of elements that need to know to what object they belong. How do I do that


This looks like a decent enough solution to me for the above requirement. I wouldn't know a better one off-hand.

Quote

{ // This is what is all about : I want to be SURE a TickerIndex can only be added to ONE StockExchange and I also must know to WHAT StockExchange it has been added


This is a different requirement though. What you achieve with your code is that you cannot add a new TickerIndex to the StockExchange if it is already assigned a StockExchange. There is nothing stopping someone from resetting the StockExchange property and adding the TickerIndex to an other StockExchange.

What I would do is create a TickerIndexManager or somesuch that keeps a list of all TickerIndex objects and which StockExchange they are part of. If you only allow the creation of TickerIndex objects through the Manager you can assure a TickerIndex is never added to more than one StockExchange.

Let me know if this doesn't make sense.

Erik
Was This Post Helpful? 0
  • +
  • -

#3 SoftwareTester  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 11-August 08

Re: How to reference back and forth

Posted 17 June 2009 - 01:23 AM

Yes, you're right, using a TicketIndexManager is much better.
But i still have some questions
a) would it be best to use a static TicketIndexManager (one instance possible only [just like in life --> having several managers will cause problems :D ])?

B) I'm not sure if I understood correct

Quote

What you achieve with your code is that you cannot add a new TickerIndex to the StockExchange if it is already assigned a StockExchange. There is nothing stopping someone from resetting the StockExchange property and adding the TickerIndex to an other StockExchange.

I thought
{public class TickerIndex
public StockExchange
{
get
{
return stockExchange;
}
set
{
if ((stockExchange == null) && (value != null))
{ // Should be able to set this ONE time
stockExchange = value;
} 
}


would prevent resetting 'stockExchange'. Am I wrong?

c) If I would like to delete a StockExchange (maybe from a StockExchangeManager ?) there will (/might) be TickerIndexes in the list of TickerIndexManager. How can I make sure those references will be removed as well?

This post has been edited by SoftwareTester: 17 June 2009 - 02:05 AM

Was This Post Helpful? 0
  • +
  • -

#4 eburger  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 16-June 09

Re: How to reference back and forth

Posted 17 June 2009 - 02:47 AM

Using a static TickerIndexManager (or another implementation of the Singleton pattern) would be what I would do unless there is code i need to execute on object creation (i.e. in the constructor).

And you are right, your code will prevent the StockExchange property from being reset. As an alternative implementation, you could use a constructor to set the StockExchange property and make the property read-only. I think that might be a cleaner solution.

What your code doesn't prevent is someone creating the same TickerIndex twice (for example with the same name) but with different StockExchanges. That's what the TickerIndexManager would take care of.

You can have the Delete method of your StockExchange object use the TicketIndexManager to delete all related TickerIndex objects. And while you are creating Managers, a StockExchangeManager wouldn't be a bad idea. After all, you might have the requirement that StockExchange objects need to be unique, as well.

Hope this helps,

Erik
Was This Post Helpful? 0
  • +
  • -

#5 SoftwareTester  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 11-August 08

Re: How to reference back and forth

Posted 17 June 2009 - 05:55 AM

Yes, I implemented StockEchangeManager already before I received your answer and I have been using same article you referred for Singleton [using Fifth version]) thinking along the lines of letting TickerIndexManager remove all references called from StockExchange.Delete.
Indeed my TickerIndexManager already checked for duplicate StockExchanges and StockExchangeManager for duplicate TickerIndexes

I use this code
	public sealed class TickerIndexManager
	{ // Manages TickerIndexes
		// *********** Begin creation of a thread-safe TickerIndexManager singleton without use of locking
		// see http://www.yoda.arachsys.com/csharp/singleton.html (using fifth version)
		public static TickerIndexManager Instance
		{
			get
			{
				return CreateSingletonTickerIndexManager.instance;
			}
		}

		class CreateSingletonTickerIndexManager
		{ // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
			static CreateSingletonTickerIndexManager()
			{
			}

			internal static readonly TickerIndexManager instance = new TickerIndexManager();
		}
		// *********** End creation of a thread-safe TickerIndexManager singleton without use of locking

	
		private List<TickerIndex> Indexes = null;	// List containing all TickerIndexes 

		public TickerIndexManager()
		{ // Constructor : create a list of TickerIndex
			Indexes = new List<TickerIndex>();
		}

		public bool DeleteIndex(TickerIndex IndexToDelete)
		{
			bool bDeleted = false;
			if (IndexToDelete != null)
			{
				if (bDeleted = Indexes.Remove(IndextoDelete))
				{ // Removed from Indexes, but IndexTodelete (can) still be linked to Exchange
					if (IndexToDelete.Exchange != null)
					{ // First remove it from its StockExchange
						IndexToDelete.Exchange.DeleteIndex(IndecToDelete);
					}
				}
			}
			return bDeleted;
		}

// ***** In class StockExchange : 
		~StockExchange()
		{ // Destructor : make TickerIndexManager aware it has to delete TickerIndexes assigned to this StockExchange
			TickerIndexManager instance = TickerIndexManager.Instance;
			int Count = indexes.Count;
			while (0 < Count--) 
											   {
													indexes[Count]Exchange = null;
													instance.DeleteIndex(indexes[Count]);
											   }
		}

		public bool DeleteIndex(TickerIndex Index)
		{ // Removing a TickerIndex from a StockExchange
			bool bRemoved = indexes.Remove(Index);
			if (bRemoved == true)
			{
				Index.Exchange = null;
				TickerIndexManager.Instance.DeleteIndex(Index);
			}
			return bRemoved;
		}

// ****** In class StockExchangeManager
		public bool DeleteExchange(StockExchange ExchangeToDelete)
		{
			bool bDeleted = false;
			if (ExchangeToDelete != null)
			{
				bDeleted = true;
				Exchanges.Remove(ExchangeToDelete);
																ExchangeToDelete = null;
			}
			return bDeleted;
		}




Would the code above delete it correctly?
Intended:
a) StockExchangeManager::DeleteExchange to be called for deleting a StockExchange
B) Destructor of StockExchange will invoke TickerIndexmanager for each TickerIndex that will delete the TickerIndex
c) In case a particular TicketIndex has to be deleted this can be done by calling TicketIndexManager::DeleteIndex and it will remove it from its StockExchange as well

This post has been edited by SoftwareTester: 17 June 2009 - 06:25 AM

Was This Post Helpful? 0
  • +
  • -

#6 eburger  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 16-June 09

Re: How to reference back and forth

Posted 17 June 2009 - 06:39 AM

View PostSoftwareTester, on 17 Jun, 2009 - 04:55 AM, said:

Would the code above delete it correctly?
Intended:
a) StockExchangeManager::DeleteExchange to be called for deleting a StockExchange
B) Destructor of StockExchange will invoke TickerIndexmanager for each TickerIndex that will delete the TickerIndex
c) In case a particular TicketIndex has to be deleted this can be done by calling TicketIndexManager::DeleteIndex and it will remove it from its StockExchange as well


Using a destructor will not have the effect you are looking for, as it is not called deterministically. This is a common error made by people who come from a C++ background (including me) (more info here). You should use a destructor IF AND ONLY IF you have unmanaged resources to clean up.

I would call TickerIndexManager.DeleteIndex for all indexes in a StockExchange when you call StockExchangeManager.Delete().

Also, be aware of a possible infinite loop. When you call StockExchange.DeleteIndex it calls TickerIndexManager.DeleteIndex, which in turn calls StockExchange.DeleteIndex, which in turn calls TickerIndexManager.DeleteIndex, etc. It might work but I think you are making the code very difficult for yourself and others to maintain later.

You have a StockExchangeManager. I suggest using that to handle operations like Delete. That way the TickerIndex and StockExchange objects are pure data classes (a.k.a. POCO classes).

I hope this helps.

Erik

EDIT: Just a thought. If TickerIndex objects have no meaning unless they're part of a StockExchange, you can do away with the TickerIndexManager altogether and do your work through the StockExchangeManager. It could then expose the list of StockExchange objects as an indexed property of type List, allowing you to use it like: StockExchangeManager[ <StockExchange> ].AddTickerIndex( ... ), StockExchangeManager[ <StockExchange> ].Clear(), etc. Even a function like StockExchangeManager.GetTickerIndex( ... ) would work. You could use LINQ to search through the StockExchange objects and return the TickerIndex object. Also, you could use Implicit Type Conversion to be able to say something like StockExchangeManager["NASDAQ"].AddTickerIndex( ... )

This post has been edited by eburger: 17 June 2009 - 06:51 AM

Was This Post Helpful? 0
  • +
  • -

#7 SoftwareTester  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 11-August 08

Re: How to reference back and forth

Posted 17 June 2009 - 07:56 AM

If you want to delete a StockExchange calling StockExchangeManager.Delete(ExchangeToDelete) it requires an additional class (StockExchangeManager) to have knowledge about the implementation of StockExchange because it needs to know about the existence (and it being 'linked' by TickerIndexManager) of TickerIndex, whereas if StockExchangeManager ONLY handles StockExchange objects it just handles what it created before.

public bool StockExchangeManager.Delete(ExchangeToDelete)
{
bool bDeleted = false;
if (bDeleted = Indexes.Remove(ExchangeToDelete))
{
foreach(TicketIndex TI in ExchangeToDelete)
{
TickerIndexManager.Instance.DeleteIndex(TI);
}
}
return bDeleted;
}



This works, but what happens if TickerIndexManager.Instance.Delete(IndexToDelete) being called in another way (NOT by StockExchangeManager) ? The result would be that IndexToDelete would no longer be in the Indexes of the TickerIndexManager object but it WILL be in the List<TickerIndex>indexes of StockExchange.

I think one way or another both StockExchange and TickerIndexManager need to be called and recursion cannot be avoided.

A possibility would be
		public bool StockExchange.DeleteIndex(TickerIndex Index)
		{ // Deleting a TickerIndex from a StockExchange
			bool bDeleted = indexes.Remove(Index);
			if (bDeleted == true)
			{ // Remove Index from TickerIndexManager as well
			  // Calling TickerIndexManager.Instance.DeleteIndex(Index) will cause recursion
			  // but as Index has been removed from indexes this will not cause in INFINITE loop
				TickerIndexManager.Instance.DeleteIndex(Index);
			}
			return bDeleted;
		}
  
		public bool TickerIndexManager.DeleteIndex(TickerIndex IndexToDelete)
		{
			bool bDeleted = false;
			if (IndexToDelete != null)
			{
				if (bDeleted = Indexes.Remove(IndexToDelete))
				{ // Removed from Indexes, but IndexToDelete (can) still be linked to Exchange
					if (IndexToDelete.Exchange != null)
					{ // First remove it from its StockExchange
					  // This will cause recursion but as IndexToDelete has been removed from Indexes
					  // no infinite loop will occur
						IndexToDelete.Exchange.DeleteIndex(IndexToDelete);
					}
				}
			}
			return bDeleted;
		}


As IndexToDelete will be removed from the list it is in (both in TickerIndexManager and StockExchange) BEFORE the call to the 'other class' will be made, recursion call will occur but it will no longer find IndexToDelete in the list and because of that not cause another recursion.
Anyway, disadvantage of this method is that both classes have knowledge about the implementation (i.e. IndexToDelete being in a list that needs updating) of the other class.

But wouldn't it be a better solution to let TickerIndex handle it?
		public void TickerIndex.Delete()
		{ // Delete the object : remove it from lists its in
			if (exchange != 0) exchange.DeleteIndex(this);
			TickerIndexManager.Instance.DeleteIndex(this);
		}

							   public bool StockExchange.DeleteIndex(TickerIndex IndexToDelete)
{
bool bDeleted = false;
if (bDeleted = indexes.Remove(IndexToDelete)) IndexToDelete.Delete();
return bDeleted;
}

							   public bool TickerIndexManager.DeleteIndex(TickerIndex IndexToDelete)
{
bool bDeleted = false;
if (bDeleted = Indexes.Remove(IndexToDelete)) IndexToDelete.Delete();
return bDeleted;
}



By using this method only TickerIndex needs to know it appears in a list in StockExchange and in TickerIndexManager.
In fact, by calling both
TickerIndexManager.instance.Add(this);
and
StockExchange.Add(this);
from within the constructor of the TickerIndex object, the class already knows it appears in those 2 lists, so it is logical to remove itself while deleting.

What do you think about this?

Also : In C++ times it has been possible to perform a
delete IndexToDelete;
or
delete ExchangeToDelete;
and the destructor will be called but TicketIndexManager would still contain a reference to IndexToDelete

If it is not possible to delete an object if it still appears in a list in C#, there is no problem with my approach. But if it is possible : do I need to do something else ?
Was This Post Helpful? 0
  • +
  • -

#8 eburger  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 16-June 09

Re: How to reference back and forth

Posted 17 June 2009 - 08:17 AM

View PostSoftwareTester, on 17 Jun, 2009 - 06:56 AM, said:

This works, but what happens if TickerIndexManager.Instance.Delete(IndexToDelete) being called in another way (NOT by StockExchangeManager) ?

Quote

By using this method only TickerIndex needs to know it appears in a list in StockExchange and in TickerIndexManager.
In fact, by calling both
TickerIndexManager.instance.Add(this);
and
StockExchange.Add(this);
from within the constructor of the TickerIndex object, the class already knows it appears in those 2 lists, so it is logical to remove itself while deleting.

What do you think about this?


That depends on the answer to the following question: does it make sense to let TickerIndex be an autonomous class? I.o.w. does it make sense to be able to create "loose" TickerIndex objects which will never be added to a StockExchange?

If the answer is NO, then I would drop the TickerIndexManager and let the StockExchangeManager handle all operations since in effect, any operation on a TickerIndex also operates on a StockExchange; you add a TickerIndex TO a StockExchange, you delete a TickerIndex FROM a StockExchange, etc. You could see StockExchange as a collection of TickerIndexes (plus some extra properties).

If the answer is YES, then you are close to a solution. But by giving the TickerIndex knowledge of the StockExchange object's methods, you are creating a circular dependency between the two which IMHO you should avoid at all costs. Code like this can be very, very hard to maintain. I always try to adhere to the Law of Demeter and Orthogonality.

Note that these are by no means laws, but I find that following them my code becomes cleaner, more OO and much easier to maintain and extend. Build for the future, not the present. :)

Quote

If it is not possible to delete an object if it still appears in a list in C#, there is no problem with my approach. But if it is possible : do I need to do something else ?


The reference to the object (which is in effect what you are storing in your list) will not be deleted while there are still instances out there. So I think you're good.

Erik

This post has been edited by eburger: 17 June 2009 - 08:18 AM

Was This Post Helpful? 0
  • +
  • -

#9 SoftwareTester  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 11-August 08

Re: How to reference back and forth

Posted 17 June 2009 - 10:49 AM

Quote

That depends on the answer to the following question: does it make sense to let TickerIndex be an autonomous class? I.o.w. does it make sense to be able to create "loose" TickerIndex objects which will never be added to a StockExchange?

hmm, don't know that by now to be honest.
I presume an index being linked to ONE exchange.
But part of an index are the tickers (stocls) it is calculated from. So a StockExchange can have several TickerIndexes (1:n) and each TickerIndex will have several (1:n) Tickers.
But it is intended to make it possible to group Tickers from SEVERAL Exchanges into a TickerIndex (so maybe it would be better to change the name TickerIndex into TickerGroup or TickerList).
In such case a (unique) name should be supplied and much functionality would be the same. Using a derived class both Group and StockExchange derive from seems logical.


If I drop TicketIndexManager but instead use a
private static List<TicketIndex>Indexes
in class TicketIndex I can add them to the list and delete them from the list inside that class
By doing that only
public bool StockExchange.Add(TicketIndex IndexToAdd)
{
bool bAdded = false;
if ((IndexToAdd != null)  && (IndexToAdd.Exchange == this) &&
(Indexes.IndexOf(IndexToAdd) < 0))
{
bAdded = true;
Indexes.Add(IndexToAdd);
}
return bAdded;
}

public bool StockExchange.Delete(TicketIndex IndexToDelete)
{
bool bDeleted = Indexes.Remove(IndexToDelete);
if (bDeleted == true) IndexToDelete.Delete();
return bDeleted;
}


will have knowledge about TicketIndex.
To be exact:
"Add" knows about IndexToAdd.Exchange being the value referring to the StockExchange IndexToAdd has been attached
"Delete" knows about the necessity to call IndexToDelete.Delete()

public void TickerIndex.Delete()
{
if (Exchange != null) Exchange.Delete(this);
Indexes.Remove(this);
}

public TickerIndex.TickerIndex(string NameTicker, StockExchange OriginExchange)
{
exchange = OriginExchange;
OriginExchange.Add(this); // Adding it to StockExchange.Indexes
Indexes.Add(this); // Adding to the List<TickerIndex>
}


Now TickerIndex.Delete knows it has to remove itself from the list in StockExchange and the constructor knows it has to add itself to the list in StockExchange

Overal now only a coupling between StockExchange and TickerList exists. Of course I would like to get rid of that as well, but how? I don't see this will change if the list will be maintained by StockExchangeManager
Was This Post Helpful? 0
  • +
  • -

#10 eburger  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 11
  • Joined: 16-June 09

Re: How to reference back and forth

Posted 21 June 2009 - 12:24 PM

View PostSoftwareTester, on 17 Jun, 2009 - 09:49 AM, said:

I presume an index being linked to ONE exchange.
But part of an index are the tickers (stocls) it is calculated from. So a StockExchange can have several TickerIndexes (1:n) and each TickerIndex will have several (1:n) Tickers.
But it is intended to make it possible to group Tickers from SEVERAL Exchanges into a TickerIndex (so maybe it would be better to change the name TickerIndex into TickerGroup or TickerList).
In such case a (unique) name should be supplied and much functionality would be the same. Using a derived class both Group and StockExchange derive from seems logical.


Yes that would make sense.

Quote

Now TickerIndex.Delete knows it has to remove itself from the list in StockExchange and the constructor knows it has to add itself to the list in StockExchange

Overal now only a coupling between StockExchange and TickerList exists. Of course I would like to get rid of that as well, but how? I don't see this will change if the list will be maintained by StockExchangeManager


I am not a big fan of objects knowing how to 'add themselves' or 'remove themselves'. It's definitely an accepted way to go but I am part of an other school of thought, so to speak.

That said, what you still have now is a bidirectional coupling where StockIndex knows about StockExchange and the other way around. Introducing a StockExchangeManager will get rid of that, introducing only a unidirectional coupling, where the StockExchange knows about the TickerIndex. Setting the Exchange property of the TickerIndex will happen in the constructor as you have it now. Deletion of the TickerIndex from the StockExchange will happen through the StockExchangeManager, which deletes both the TickerIndex object and removes its reference from the owning StockExchange.

I hope that clears up my point a bit. Know that nothing you are doing is wrong per se so feel free to go your own way. It's more important to know there are alternatives than to actually use them.

Hope this helps.

Erik

This post has been edited by eburger: 21 June 2009 - 12:26 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1