Задача кругового класса - PullRequest
2 голосов
/ 18 октября 2010

Я занимаюсь разработкой приложения на C # и у меня есть класс Employee и класс Organization.

Объект Employee имеет в качестве внутреннего члена Organization, а объект Organization имеет члена Employee для указания лидера Org.

Будут ли какие-либо проблемы с этой установкой, которые могут привести к бесконечному циклическому созданию экземпляров?

Редактировать:

Я только что попробовал запустить код, и, похоже, возникла проблема,Объект employee создает экземпляр объекта Organization, а объект Organization пытается создать экземпляр объекта employee.Они оба подключаются к базе данных, чтобы заполнить свои данные

Это происходит до тех пор, пока на моем сервере SQL не закончатся соединения.Есть ли альтернатива тому, что я делаю?

Ответы [ 3 ]

4 голосов
/ 18 октября 2010

Нет.Это будет хорошо скомпилировать.Компилятор C # достаточно умен, чтобы учитывать все типы, даже если они «еще не скомпилированы».Как и в Java, определение / объявление одно и то же (это отличается, скажем, от C / C ++).

2 голосов
/ 18 октября 2010

Будут ли какие-либо проблемы с этой настройкой, которые могут привести к бесконечному циклическому созданию экземпляров?

Типами ссылок по умолчанию являются 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;
  }
}

Обратите внимание, что внедрение зависимости не было изобретено для решения этой проблемы, но оно будет работать в этом сценарии.С ним вы можете быть спокойны, зная, что никогда больше не решите эту проблему.

1 голос
/ 18 октября 2010

Проблема, с которой вы столкнулись, вряд ли связана с самим C #, но, вероятно, ваш код находится в бесконечном цикле, когда Организация запрашивает у Сотрудника информацию, которая заставляет Сотрудника снова запрашивать у Организации ту же информацию ....

Все, что вам нужно сделать, это разорвать эту ссылку, чтобы запрос информации об Организации не связывал вызов с ее сотрудниками (и наоборот).т.е. если вам нужна полная информация об организации, вместо

org.GetAbsolutelyAllInformation();

вы бы позвонили

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

Если вы должны вернуть информацию одним комком,затем вместо того, чтобы возвращать информацию в новом объекте, передайте «пустой» объект, который нужно заполнить. Если вы вызываете объект, который уже заполнен, возвращайте кэшированную информацию, а не извлекайте ее из базы данных снова.Таким образом, не имеет значения, в каком порядке вызываются ваши методы, они просто будут заполнять информацию об органе или лидере в передаваемом вами объекте, и «цикл» будет остановлен на следующей итерации, когда обнаружится, что всеинформация была заполнена.

В общем, одним из способов снизить риск возникновения такого рода петель, в первую очередь, было бы то, чтобы «Лидер» организации был идентификатором (например, номером сотрудника), а непрямая ссылка.Это поощряет любого программиста, использующего этот код, получить идентификатор лидера, а затем просмотреть информацию о лидере как отдельный шаг.

...