Why objects are orphan, when creator exist
Consider following code
public class City
{
public string Name { get { return "New York"; } }
Building empEstate;
Building nyTimes;
public void Init()
{
// I hate passing "this" to all object
empEstate = new EmpEstate(this);
setSomeProperty(empEstate);
// any one can create new object of some other city
// and pass to the building
nyTimes = new NYTimes(this);
...
开发者_开发问答 other = new OtherBuildings(this)
}
public void PrintAddresses()
{
empEstate.Print();
nyTimes.Print();
...
other.Print();
}
}
public abstract class Building {
City _city;
public Building(City city){
this._city = city;
}
public abstract string Name { get;}
public void Print(){
Console.WriteLine(this.Name);
Console.Write(",");
Console.WriteLine(this._city.Name);
}
}
First thing I want better solution to this approach. Print is just an example. Actually each building object raise some event to City object. I don't want to add handler to each building as there could be several buildings in city. Also I do not want to add each of them into list, as it is two task for each building (one initialization and second add to list, one forget to add to list when writing new building). For this, I want caller to be automatically available to callee, like Parent property of control (though it was added to this.Controls)
Using memory, can we know who is the parent of current object. How does GC knows that object is not being referenced (including creator). Can't we create a method (safe or unsafe) using memory to identify the caller object. I see we can use StackTrace to see the call hirarchy, can we intercept here when a new object is being created.
Building factory on city solved my problem of passing this to each object
public interface ICity
{
string Name { get; }
}
public abstract class City : ICity
{
public T CreateBuilding<T>()
{
T buildingInstance = Activator.CreateInstance<T>();
((IBuilding)buildingInstance).SetCity(this);
return buildingInstance;
}
public abstract string Name { get; }
}
interface IBuilding
{
ICity City { get; }
void SetCity(ICity city);
}
public abstract class Building : IBuilding
{
private ICity _city;
public ICity City { get { return _city; } }
public void IBuilding.SetCity(ICity city)
{
this._city = city;
}
public abstract string Name { get; }
public void Print()
{
Console.WriteLine(this.Name);
Console.Write(",");
Console.WriteLine(this._city.Name);
}
}
public class EmpEstate : Building
{
public override string Name { get { return "Emp State"; } }
}
public class NYTimes : Building
{
public override string Name { get { return "NY Times"; } }
}
public class NewYorkCity : City
{
public override string Name { get { return "New York"; } }
EmpEstate empEstate;
NYTimes nyTimes;
public void Init()
{
// Now I dont need to pass this
empEstate = this.CreateBuilding<EmpEstate>();
setSomeProperty(empEstate);
// now any one cannot create building in new your and
// say it belongs to Philedelphia :)
nyTimes = this.CreateBuilding<NYTimes>();
}
public void PrintAddresses()
{
empEstate.Print();
nyTimes.Print();
}
}
Problem was there were several classes already created and for new functionality we needed the creator object in the base class of Building Object. We did not wanted to modify the constructor of each class and pass this object to each. And City class (in example) was basically code on plugin side, so allowing them to pass city (if plugin developer pass wrong city) may disturb the functionality of entire app. So modifying the plugin base solved my purpose. Suggestions are welcome.
There is no logical "owner" of an object. Inspecting the stack trace is... not usually ideal. By comparison to Parent
, that is not very different to your existing approach - merely that is set via methods/properties rather than in the constructor.
If the city is only necessary for the context of methods like Print
, why not pass it in as a parameter, i.e. nyTimes.Print(this)
etc. If you might need other values, rather than taking lots of parameters, consider using some kind of context object that has a city - i.e.
class PrintContext {
public City City {get;private set;}
// other stuff...
public PrintContext(City city/*, other stuff...*/) {
City = city;
}
}
I think you are misusing the terms parent and creator. The object that created the instance has no special relationship with the instance (e.g. factories create objects, but do not maintain references to them), so, in general, there is no way to find out who or what created a concrete instance.
In the same sense, parent has no meaning on a general object. We can somehow infer that the Form is parent to the TextBox, but that is not a special relationship. It this case it just means that the TextBox is in the form's Contols collection, and that it's Parent is set to the Form.
You are right that this could potentially lead to inconsistencies (Form1 thinks that TextBox is it's child, but the TextBox thinks that it's Parent is Form2), but I do not know of, and don't think there is a better solution of this kind of relationship than the Children
collection / Parent
reference.
Picking a few of your many questions:
I hate passing this
Why? You are telling the building which city it belongs to. How else could you do this. I see that as a common idiom for wiring objects together.
Also I do not want to add each of them into list, as it is two task for each building (one initialization and second add to list, one forget to add to list when writing new building).
I'm not clear what list you want to add them to, but your concern about "forgetting" is overcome if you do the work in the base constructor:
public Building(City city){
this._city = city;
// add the building to the list here - nothing to "forget"
}
As for GC, once a creator has created something there is no relationship between them unless you choose to retain a reference. You have done that with
empEstate = new EmpEstate(this);
so as long as the City is not a candidate for garbage collectio then the EmpState won't be either.
精彩评论