How to deal with passing a parent object as an argument?

I'm not sure what I'm doing is completely invalid or just bad practice, but I have a class, let it call it Bar , which is a field of some parent class, call Foo and one of the Bar methods needs to pass an instance parent Foo as an argument. This seems like a terrible and dirty idea, but I can't think of a better way to do this. Foo effectively stores multiple List<Bar> , Bar , ConcurrentDictionary<string,Bar> or similar and is used to allow me to create all of my Bar instances without duplicating data.

The principle of the code is something like this:

 public class Foo { public List<Bar1> bar1List {get;set;} public List<Bar2> bar2List {get;set;} } public abstract class Bar { //EDITED TO IMPROVE EXAMPLE public int Value {get;set;} public void DoSomething(Foo parentFoo) { } } public class Bar1 : Bar { public override void DoSomething(Foo parentFoo) { //EDITED TO GIVE AN EXAMPLE OF DoSomething() this.Value = this.Value + parentFoo.bar2List[0].Value: } } public class Bar2 : Bar { public override void DoSomething(Foo parentFoo) { //some other code } } Foo foo = new Foo() //populate foo somehow foo.bar1List[0].DoSomething(foo); //this is what looks very odd to me and feels kind of like a circular reference. The code will never be circular in that if I want to change bar1List within DoSomething() I will do it by "this", not foo.bar1List. 

I was thinking about making each List<BarX> (where X is a number) a static BarX field, but this does not work, since everything is multithreaded, and I need several instances of List<BarX> ; I thought about accessing the parent using standard methods, but I don’t see how it does not get messy if I have two parents on one List<BarX> . Any ideas / hints? I do not want to move the DoSomething method from Bar .

EDITING TO DESCRIBE A ACTUAL PROBLEM: As mentioned earlier, Foo functions as a repository of all the various Bar instances; all instances of Bar intertwined, so Bar1 may contain a List<Bar> . As a program input, one Bar s family is specified, for example List<Bar1> ; other BarX , etc. etc. then created from this list as required, using the loading of configuration files and logic. In total there are 9 Bar flavors located in non-linear mode, for example. my first instance of Bar1 may need an instance of Bar7 , which in turn requires another instance of Bar1 (which was not in the initial List<Bar1> ), etc. Each BarX flavor has a Generate() method that replaces DoSomething() to determine how to build it. This layout lends itself perfectly to flow, so it is imperative that all these instances take up parallel space, where the main idea is IfExists, returns it, and assigns the / List / whatever field; otherwise, create it and add it to ConcurrentDictionary .

+5
source share
1 answer

One way to achieve this goal is to implement an ObservableCollection for your Foo class to listen for changes inside the list, and after adding / removing items, you can add a parent to the child of the Bar.

Thus, your method should not refer to the parent, but it can access it through the Property Parent , which will be of type Foo .

Since they all refer to the same Foo instance inside the Foo instance, you will not have duplicate data.

As an example of such an implementation, you can do this as follows:

First, define an interface that provides easy access to the Parent property.

 public interface IChild<T> { T Parent { get; } } 

And we could do the same for the DoSomething Bar method

 public interface IBar { void DoSomething(); } 

And we implement two interfaces inside the abstract version of Bar, leaving the abstract DoSomething methods

 public abstract class Bar : IChild<Foo>, IBar { private Foo parent; public Foo Parent { get { return parent; } set { parent = value; } } public abstract void DoSomething(); } 

and implementations of two versions of Bar, for example, for example:

 public class Bar1 : Bar { public override void DoSomething() { if (this.Parent == null) { throw new ArgumentException("Parent cannot be null"); } // code against parent Console.WriteLine("Bar 1 doing something"); } } public class Bar2 : Bar { public override void DoSomething() { if (this.Parent == null) { throw new ArgumentException("Parent cannot be null"); } // code against parent Console.WriteLine("Bar 2 doing something"); } } 

Then you need to make changes to your Foo class, which registers in the collection (Bar1Collection, Bar2Collection) and offers a way to listen for changes in the collection. It also implements the IDisposable interface so that we can unregister from CollectionChanged events when we no longer need the Foo class

 public class Foo : IDisposable { private readonly IList<Bar> bar1Collection = new ObservableCollection<Bar>(); public IList<Bar> Bar1Collection { get { return bar1Collection; } } private readonly IList<Bar> bar2Collection = new ObservableCollection<Bar>(); public IList<Bar> Bar2Collection { get { return bar2Collection; } } protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (var item in e.OldItems) { if (item is Bar) { var bar = item as Bar; bar.Parent = null; } } } if (e.NewItems != null) { foreach (var item in e.NewItems) { if (item is Bar) { var bar = item as Bar; bar.Parent = this; } } } } protected void RegisterCollection(INotifyCollectionChanged collection) { if (collection == null) { return; } collection.CollectionChanged += OnCollectionChanged; } protected void UnregisterCollection(INotifyCollectionChanged collection) { if (collection == null) { return; } collection.CollectionChanged -= OnCollectionChanged; } public Foo() { RegisterCollection(Bar1Collection as INotifyCollectionChanged); RegisterCollection(Bar2Collection as INotifyCollectionChanged); } private bool isDisposed = false; protected virtual void Dispose(bool disposing) { if (!disposing || isDisposed) { return; } isDisposed = true; UnregisterCollection(Bar1Collection as INotifyCollectionChanged); UnregisterCollection(Bar2Collection as INotifyCollectionChanged); } public void Dispose() { Dispose(true); } } 

As a test method, this console program could work against it

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Diagnostics; namespace BarFoo { class Program { static void Main(string[] args) { Foo foo1 = new Foo(); Bar bar1 = new Bar1(); Bar bar2 = new Bar2(); foo1.Bar1Collection.Add(bar1); foo1.Bar2Collection.Add(bar2); Debug.Assert(bar1.Parent != null); Debug.Assert(bar2.Parent != null); bar1.DoSomething(); bar2.DoSomething(); Console.WriteLine("Done"); Console.ReadLine(); foo1.Dispose(); } } } 
+2
source

All Articles