C# 当造物主存在时,为什么对象是孤立的

C# 当造物主存在时,为什么对象是孤立的,c#,design-patterns,memory-management,C#,Design Patterns,Memory Management,考虑以下代码 public class City { public string Name { get { return "New York"; } } Building empEstate; Building nyTimes; public void Init() { // I hate passing "this" to all object em

考虑以下代码

    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);
        }
    }
  • 首先,我希望更好地解决这个问题。打印只是一个例子。实际上,每个建筑对象都会向城市对象引发一些事件。我不想在每个建筑中添加处理程序,因为城市中可能有多个建筑。另外,我不想将它们都添加到列表中,因为每个建筑都有两个任务(一个初始化,第二个添加到列表,一个在编写新建筑时忘记添加到列表)。为此,我希望调用者自动对被调用者可用,就像控件的父属性一样(尽管它被添加到了this.Controls中)

  • 使用内存,我们可以知道谁是当前对象的父对象。GC如何知道对象未被引用(包括创建者)。我们不能使用内存创建一个方法(安全或不安全)来标识调用方对象吗。我知道我们可以使用StackTrace来查看调用hirarchy,我们可以在创建新对象时在这里拦截

  • 对象没有逻辑上的“所有者”。检查堆栈跟踪是。。。通常并不理想。与父级相比,这与您现有的方法没有太大区别-只是通过方法/属性而不是在构造函数中设置

    如果该城市仅适用于诸如“代码>打印< /代码>等方法的上下文,为什么不将其作为参数传递,即<代码> NyTimes?打印(此)< /代码>等。如果您可能需要其他值,而不是获取大量参数,请考虑使用具有城市的上下文对象-即

    class PrintContext {
         public City City {get;private set;}
         // other stuff...
         public PrintContext(City city/*, other stuff...*/) {
              City = city;
         }
    }
    

    我认为你误用了父母和创造者这两个词。创建实例的对象与实例没有特殊关系(例如,工厂创建对象,但不维护对它们的引用),因此,一般来说,无法确定是谁或是什么创建了具体实例。
    在同样的意义上,父对象对一般对象没有意义。我们可以推断表单是文本框的父对象,但这不是一种特殊的关系。在这种情况下,它只意味着文本框位于表单的Contols集合中,并且它的父项设置为表单


    您是对的,这可能会导致不一致(Form1认为TextBox是它的子项,但TextBox认为它的父项是Form2),但我不知道,不要认为这种关系有比
    儿童
    集合家长参考更好的解决方案。

    从你的许多问题中挑选一些:

    我讨厌传递这个

    为什么??你在告诉那栋楼它属于哪个城市。你还能怎么做呢。我认为这是将对象连接在一起的常见习惯用法

    另外,我不想将它们都添加到列表中,因为这是两项任务 对于每个建筑(一个初始化和第二个添加到列表,一个 写新建筑时忘记添加到列表)

    我不清楚您想将它们添加到哪个列表中,但如果您在基本构造函数中进行工作,您对“遗忘”的担忧就不会出现了:

        public Building(City city){
            this._city = city;
            // add the building to the list here - nothing to "forget"
        }
    
    至于GC,一旦创建者创建了一些东西,它们之间就没有关系,除非您选择保留引用。你已经和我一起做了

    empEstate = new EmpEstate(this); 
    

    因此,只要城市不是垃圾收集的候选城市,那么EmpState也不会成为垃圾收集的候选城市。

    在城市上建造工厂解决了我将垃圾收集传递给每个对象的问题

    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();
            }
        }
    
    公共接口
    {
    字符串名称{get;}
    }
    公共抽象类城市:城市
    {
    公共建筑(
    {
    T buildingInstance=Activator.CreateInstance();
    ((i建筑)站姿)设置城市(本);
    回归建筑立场;
    }
    公共抽象字符串名称{get;}
    }
    界面IBuilding
    {
    城市{get;}
    无效城市(城市);
    }
    公共抽象类构建:IBuilding
    {
    私立城市;
    公共城市{get{return{u City;}
    公共空间IBuilding.SetCity(城市)
    {
    这个。_city=城市;
    }
    公共抽象字符串名称{get;}
    公开作废印刷品()
    {
    Console.WriteLine(此.Name);
    控制台。写(“,”;
    Console.WriteLine(此城市名称);
    }
    }
    公共类国家:建筑
    {
    公共重写字符串名称{get{返回“Emp状态”;}
    }
    《纽约时报》公共课:建筑
    {
    公共重写字符串名称{get{return“NY Times”;}
    }
    公共课纽约市:城市
    {
    公共重写字符串名称{get{return“New York”;}
    EmpEstate EmpEstate;
    纽约时报;
    公共void Init()
    {
    //现在我不需要通过这个考试
    empEstate=this.CreateBuilding();
    setSomeProperty(empEstate);
    //现在,任何人都无法在新的和中创建建筑
    //说它属于菲利德尔菲亚:)
    nyTimes=this.CreateBuilding();
    }
    公共地址()
    {
    emperstate.Print();
    Print();
    }
    }
    

    问题是已经创建了几个类,对于新功能,我们需要在Building对象的基类中使用creator对象。我们不想修改每个类的构造函数并将此对象传递给每个类。City类(在示例中)基本上是插件端的代码,所以允许他们通过City(如果插件开发者通过错误的城市)可能会干扰整个应用程序的功能。因此,修改插件库解决了我的问题。欢迎您提出建议。

    您所说的“家长”是什么意思?家长您可以说是声明或创建对象的对象。我喜欢您作为PrintContext的想法,但正如我所说的,城市需要处理每栋建筑引发的事件,在这里,这种方法行不通。