要访问父实例的属性?

时间:2018-11-21 23:48:52

标签: c# class instance system.reflection

让我们说我有一些看起来像这样的类:

我将此类称为父实例

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()

这是此问题的并发症:

  1. 无需做任何操作即可{strong>进行操作,只需复制一个ImportantInfo属性并将其传递给子实例容器的构造函数
  2. 在从子实例的ImportantInfo方法中调用时,无需

是否可以用SomeCoolStringBufMethod()来“查找” System.ReflectionBar成员的事实,并获取Foo的{​​{ 1}}属性?

3 个答案:

答案 0 :(得分:1)

你不能。

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

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

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

如果有一种方法可以使用反射来查找类的每个活动实例,则可以使用该方法以一种绕行方式解决它,但是没有办法。

一个小注意事项:将string传递给方法时,并不是在创建重复项。如果您有兴趣,请进一步了解here

答案 1 :(得分:1)

简短答案为否。

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

由于您Bar完全没有引用Foo,因此您甚至无法判断哪个Foo包含您的Bar,甚至无法确定是否您的Bar被所有Foo引用。

要弄清所有这些,您必须追溯谁在引用您的Bar

理论上,可以使用类似GC的技术来完成,但是GC确实从上到下引用搜索,这意味着从GC根到Foo然后到您的Bar,不是从下到上最佳。您可以构建外部双链接GC,例如FooBar图形。

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

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

答案 2 :(得分:1)

第二条路要走。 (而且,我不是想逗。)

  

...从父级调用子实例的ImportantInfo方法时,将SomeCoolStringBufMethod()作为参数传递。

方法是类之间如何交互的方法。引用另一个对象仅是达到最终目的的一种方法,该方法可以调用其方法并访问其属性。

我们通常不创建带有循环引用的类的理由很充分。例如,假设Text.StringBuilder。如果它具有对创建它的类的引用,而不管它如何通过构造函数,反射或其他任何方式获得该引用,该怎么办。

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

与您的班级有关:您的子班级需要什么? Bar是否需要Foo?否。它需要一个string。任何调用其方法的类都可以给它一个string。那么,为什么要把它与另一个班级配对呢?有一天,您或其他人需要在没有Bar的情况下进行Foo的工作,然后您将需要解开一个结。

如果Bar依赖于Foo来获得其ImportantProperty,这也将使单元测试非常困难。您必须创建一个Foo,然后创建一个Bar,以便Bar可以从ImportantProperty获得其Foo。如果它依赖于string,则很容易测试。该测试只需创建一个string

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

几乎可以肯定,在子项不包含其对父项的引用的情况下进行此项工作。如果必须具有该引用,则将该引用传递给子代的构造函数将很有意义。