访问 parent 个实例的属性?

Accessing a parent instance's properties?

假设我有几个 classes 看起来有点像这些:

这个class我会调用parent实例:

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... */
    }
}

正如您在此处看到的,parent 实例 Foo 保留了一些 Bar class 实例。 在这个问题中,我将 List<Bar> 中的 Bar classes 称为 child 实例容器 。这是示例代码方式中 Bar class 的定义:

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! */
    }
}

如何从 parent 实例访问 ImportantInfo,在 child 实例容器 SomeCoolStringBufMethod() 中?

以下是这个问题的并发症:

  1. 这样做 无需 复制 ImportantInfo 属性 并将其传递给 child 实例容器的构造函数
  2. 这样做 在 child 实例的 SomeCoolStringBufMethod() 方法被调用时不必将 ImportantInfo 作为参数传入 parent .

这可能吗,比如 System.Reflection,到 'look up' 一个 Bar 是一个 Foo 的成员的事实,然后获取 Foo' s ImportantInfo 属性 ?

你不能。

您列出的两个选项确实是唯一的方法。

请记住,任何 class 实例都存在于内存中的某个地址。变量只是告诉您的应用程序在内存中的何处查找数据。当然,您可以使用反射来查找 Foo 实例的 ImportantInfo 属性,但是哪个实例呢?它应该在内存中的什么地方寻找它?您必须知道在内存中的哪个位置查看。

您知道使用变量查看内存中的哪个位置。因此,您需要以某种方式将变量传递给 Bar

如果有一种方法可以使用反射来查找 class 的每个活动实例,您可以使用它以迂回的方式计算出来,但没有办法做到这一点。

注意事项:当您将 string 传递给方法时,您并没有创建副本。更多关于 here 如果你感兴趣的话。

简短的回答是否定的。

长答案理论上是肯定的,但实际上不是。

因为你Bar根本没有提到Foo,所以你甚至不知道哪个Foo包含你的Bar,你甚至不能判断您的 Bar 是否被任何 Foo 引用。

为了计算出所有 ,您必须追溯谁在引用您的 Bar

理论上它可以使用像 GC 这样的技术来完成,但是 GC 确实从上到下进行引用搜索,这意味着从 GC root 到 Foo 然后到你的 Bar,这是不做的从下到上。您可以像 Foo,Bar Graphic 这样构建您的外部双链接 GC。

在实践中,这将花费您大量的精力,之后,您还面临着管理您自己的 Foo``Bar 图形的 GC 周期的挑战。

所以简短的回答是否定的。

第二条是要走的路。 (不,我不是想搞笑。)

...pass ImportantInfo in as an argument when the child instance's SomeCoolStringBufMethod() method is called from the parent.

方法是 classes 相互交互的方式。引用另一个 object 只是达到能够调用其方法和访问其属性的一种手段。

我们通常不创建具有循环引用的 classes 是有充分理由的。想象一下,例如 Text.StringBuilder。如果它有一个对创建它的 class 的引用,不管它是如何获得该引用的——通过构造函数、反射或其他任何方式。

StringBuilder 将如何处理该引用?除了调用 ToString() 之外,为了对 object 执行任何操作,它需要知道 object 的类型。但是如果它知道 object 的类型,那么它意味着 StringBuilder 只有在它引用了 object 的那种类型时才有效。这意味着依赖于 StringBuilderStringBuilder 的 class 只能相互结合使用。

与您的 class 相关:您的 child class 需要什么? Bar 需要 Foo 吗?不,它需要 string。任何调用它的方法的 class 都可以给它一个 string。那么为什么要将它与另一个 class 耦合呢?有一天你或其他人需要让 Bar 在没有 Foo 的情况下工作,然后你就会有一个结需要解开。

如果 Bar 依赖于 Foo 来获得它的 ImportantProperty,这也会使单元测试变得非常困难。您必须先创建一个 Foo,然后创建一个 Bar,这样 Bar 才能从 Foo 中获取其 ImportantProperty。如果它依赖于 string 那么它很容易测试。测试只需要创建一个 string.

在您的示例中,将 ImportantProperty 传递给 Bar 构造函数没有意义,因为它是 Foo 的可写 属性。这意味着 Foo 可以更改它,然后所有 Bar 将具有不同的 属性 除非您创建所有新的。 (也许 ImportantProperty 可以更改的事实是您想要返回对 parent 的引用的原因,但是将 string 传递给方法调用仍然可以解决该问题。)

如果 child 本身不包含对 parent 的引用,您几乎可以肯定地完成这项工作。如果它必须具有该引用,那么将该引用传递给 child.

的构造函数是有意义的