2

我正在开发一个 C# 应用程序,并且有一个 Employee 类和一个 Organization 类。

Employee 对象有一个 Organization 作为内部成员,Organization 对象有一个 Employee 成员来指示 Org 领导。

这种设置是否存在任何可能导致无限循环实例化的问题?

编辑:

我刚刚尝试运行代码,似乎有问题。员工对象实例化组织对象,组织对象尝试实例化员工对象。他们都连接到数据库以填写详细信息

这种情况一直在发生,直到我的 SQL 服务器连接不足。有什么替代我正在做的事情吗?

4

3 回答 3

4

不,它会编译得很好。C# 编译器足够聪明,可以考虑所有类型,即使它们“尚未编译”。与 Java 一样,定义/声明是一回事(这与 C/C++ 不同)。

于 2010-10-17T21:54:28.467 回答
2

这种设置是否存在任何可能导致无限循环实例化的问题?

引用类型是null默认的。除非您实例化一个新实例并将其分配给该变量,否则不会为该类型调用任何代码。

每个构造函数都构造另一个对象的实例吗?他们将来有可能(可能是意外)吗?如果是这样,那么是的,您可以点击您正在谈论的场景:

class A
{
  public A()
  {
    this.B = new B();
  }
  public B B;
}

class B
{
  public A A = new A(); // This is the same as instantiating the object in the ctor
}

// ...

A obj = new A(); // This calls new B, which calls new A, repeat ad infinitum

您可以通过在构造函数之外实例化另一个对象的实例来打破这样的循环。例如,在首次访问时:

class A
{
  public A()
  {
  }

  public B B
  {
    get
    {
      if(b == null)
        b = new B();
      return b;
    }
  }

  private B b;
}

class B
{
  public B()
  {
  }

  public A A
  {
    get
    {
      if(a == null)
        a = new A();
      return a;
    }
  }

  private A a;
}

// ...

A obj = new A(); // new B doesn't get called yet
obj.B.Something(); // ... Now it does...

您仍然必须小心class A不要在其构造函数中访问它自己的this.B属性,反之亦然。但是,只要不在构造函数中调用这些方法,您就可以在方法中访问这些属性。

另一种选择是进行依赖注入。这是您将依赖项传递给对象的地方,而不是让它实例化对象本身:

class A
{
  public A(B b)
  {
    this.B = b;
  }

  public B B;
}

class B
{
  public B(A a)
  {
    this.A = a;
  }

  public A A;
}

// ...

A someA = new A(
  new B(
    null)); // You have to break the cycle somewhere...
someA.B.A = someA;

// or ...

class ABFactory
{
  public static A CreateA(/* options for a */, /* options for b */)
  {
    A result = new A(
      new B(
        null));
    result.B.A = result;
    return result;
  }
}

请注意,依赖注入并不是为了解决这个问题而发明的,但它可以在这种情况下工作。有了它,你就可以高枕无忧了,因为你知道你再也不会遇到这个问题了。

于 2010-10-17T22:04:21.823 回答
1

您遇到的问题不太可能是 C# 本身,但可能是您的代码进入了无限循环,其中组织正在向员工询问导致员工再次向组织询问相同信息的信息......

您需要做的就是断开此链接,以便请求有关组织的信息不会将呼叫链接到其员工(反之亦然)。即如果你想要一个组织的完整信息,而不是

org.GetAbsolutelyAllInformation();

你会打电话给

org.GetOrganisationInformation();
org.Leader.GetEmployeeInformation();

如果必须一次性返回信息,那么与其在一个新对象中返回信息,不如传入一个“空白”对象来填充。如果调用的对象是已经填充的对象,则返回缓存的信息而不是再次从数据库中获取它。这样,调用方法的顺序无关紧要,它们只会在您传入的对象中填写 org 或 leader 信息,并且在下一次迭代时发现所有的“循环”将停止信息已填写。

一般来说,首先降低这种循环发生风险的一种方法是让组织的“领导者”成为一个 ID(例如员工编号),而不是直接引用。这鼓励任何使用此代码的程序员获取领导者 ID,然后作为单独的步骤查找领导者的信息。

于 2010-10-17T22:32:51.677 回答