让我们说我有一些看起来像这样的类:
我将此类称为父实例:
public class Foo : Disposable {
public Foo() {
Bars = new List<Bar>();
FullPath = string.empty;
}
public Foo(string szInfo) {
Bars = new List<Bar>();
ImportantInfo = szInfo;
}
~Foo() => this.Dispose(false);
/* IDisposible stuff cropped for simplicity */
public string ImportantInfo {get; internal set;}
public List<Bar> Bars {get; internal set;}
public void SomeContainerLoadMethod() {
/* Add some bars here */
Bars.Add( new Bar() );
Bars.Add( new Bar() );
/* etc... */
}
}
如您在此处看到的,父实例Foo
保留了一些Bar
类。
我将在此问题的{strong>子实例容器中,将这些Bar
类称为List<Bar>
。以下是使用示例代码方式的Bar
类的定义:
public class Bar : Disposable {
Bar() { }
~Bar() => this.Dispose(false);
/* IDisposable stuff cropped for simplicity */
public string CoolBuff {get; internal set;}
public void SomeCoolStringBufMethod() {
/* Do something to populate CoolBuff, but I need ImportantInfo! */
}
}
如何在子实例容器的ImportantInfo
中从父实例访问SomeCoolStringBufMethod()
?
这是此问题的并发症:
ImportantInfo
属性并将其传递给子实例容器的构造函数ImportantInfo
方法中调用时,无需将{1}}作为参数进行传递
父母。是否可以用SomeCoolStringBufMethod()
来“查找” System.Reflection
是Bar
成员的事实,并获取Foo
的{{ 1}}属性?
答案 0 :(得分:1)
你不能。
您列出的两个选项确实是唯一的方法。
请记住,任何类实例都存在于内存中的某个地址。变量只是告诉您的应用程序在内存中查找数据的位置。可以肯定的是,您可以使用反射来查找ImportantInfo
实例的Foo
属性,但是哪个实例呢?它应该在哪里寻找内存?您必须知道要在内存中查找的位置。
您知道使用变量在内存中查找的位置。因此,您需要以某种方式将变量传递给Bar
。
如果有一种方法可以使用反射来查找类的每个活动实例,则可以使用该方法以一种绕行方式解决它,但是没有办法。
一个小注意事项:将string
传递给方法时,并不是在创建重复项。如果您有兴趣,请进一步了解here。
答案 1 :(得分:1)
简短答案为否。
长答案在理论上是肯定的,但实际上不是。
由于您Bar
完全没有引用Foo
,因此您甚至无法判断哪个Foo
包含您的Bar
,甚至无法确定是否您的Bar
被所有Foo
引用。
要弄清所有这些,您必须追溯谁在引用您的Bar
。
理论上,可以使用类似GC的技术来完成,但是GC确实从上到下引用搜索,这意味着从GC根到Foo
然后到您的Bar
,不是从下到上最佳。您可以构建外部双链接GC,例如Foo
,Bar
图形。
在实践中,这将需要您付出大量的努力,之后,您还面临着管理Foo``Bar
图形自己的GC周期的挑战。
所以简短的答案是否定的。
答案 2 :(得分:1)
第二条路要走。 (而且,我不是想逗。)
...从父级调用子实例的
ImportantInfo
方法时,将SomeCoolStringBufMethod()
作为参数传递。
方法是类之间如何交互的方法。引用另一个对象仅是达到最终目的的一种方法,该方法可以调用其方法并访问其属性。
我们通常不创建带有循环引用的类的理由很充分。例如,假设Text.StringBuilder
。如果它具有对创建它的类的引用,而不管它如何通过构造函数,反射或其他任何方式获得该引用,该怎么办。
StringBuilder
将如何处理该引用?为了对该对象执行除调用ToString()
以外的任何操作,它需要知道该对象的类型。但是,如果知道对象的类型,则意味着StringBuilder
仅在引用了该对象类型时才起作用。这意味着依赖于StringBuilder
和StringBuilder
的类只能相互结合使用。
与您的班级有关:您的子班级需要什么? Bar
是否需要Foo
?否。它需要一个string
。任何调用其方法的类都可以给它一个string
。那么,为什么要把它与另一个班级配对呢?有一天,您或其他人需要在没有Bar
的情况下进行Foo
的工作,然后您将需要解开一个结。
如果Bar
依赖于Foo
来获得其ImportantProperty
,这也将使单元测试非常困难。您必须创建一个Foo
,然后创建一个Bar
,以便Bar
可以从ImportantProperty
获得其Foo
。如果它依赖于string
,则很容易测试。该测试只需创建一个string
。
在您的示例中,将ImportantProperty
传递给Bar
构造函数没有任何意义,因为它是Foo
的可写属性。这意味着Foo
可以更改它,然后所有Bar
都将具有不同的属性,除非您创建所有新属性。 (也许ImportantProperty
可以更改的事实是您希望返回对父级的引用的原因,但是将string
传递给方法调用仍然可以解决该问题。)
几乎可以肯定,在子项不包含其对父项的引用的情况下进行此项工作。如果必须具有该引用,则将该引用传递给子代的构造函数将很有意义。