Может ли пользовательский объект С# содержать свойство того же типа, что и сам?

Если я создал следующий Employee объект (упрощенный)...

 public class Employee
    {
        public Employee()
        {       
        }

        public String StaffID { get; set; }
        public String Forename { get; set; }
        public String Surname { get; set; }
    }

... было бы приемлемо иметь другое свойство в объекте Сотрудник с типом, также являющимся Сотрудником, чтобы хранить данные своего Менеджера (как показано ниже)?

 public class Employee
    {
        public Employee()
        {       
        }

        public String StaffID { get; set; }
        public String Forename { get; set; }
        public String Surname { get; set; }

        public Employee Manager { get; set; }
    }

Также, как лучше всего создать экземпляр объекта Сотрудник для свойства Менеджер? Очевидно, что включение this.Manager = new Employee(); в конструкторе вызовет бесконечный цикл. Лучше ли будет Менеджер класс, который наследует от Employee (хотя все свойства будут одинаковыми)?

Ответ 1

Объект может иметь ссылку на объект своего типа.

Таким образом реализуются большинство объектов типа Node.

Что касается экземпляра - вы можете передать объект Employee для использования в качестве менеджера (передача в null для no manager). Конструкторы могут иметь несколько перегрузок:

public Employee(Employee manager)
{
   this.Manager = manager;
}

Ответ 2

Да, объект может содержать ссылки на другие объекты того же класса.

И, во-вторых, я бы не создал нового сотрудника в cunstructor, но ввел его вот так:

public class Employee
{
    public Employee(Employee manager)
    {
        this.Manager = manager;
    }

    public String StaffID { get; set; }
    public String Forename { get; set; }
    public String Surname { get; set; }

    public Employee Manager { get; set; }
}

Ответ 3

Единственный сценарий, когда это невозможно, - это struct; a struct содержится напрямую (вместо ссылки на данные фиксированного размера), поэтому размер структуры Employee должен быть "размером других полей плюс размер сотрудника", который является круглым.

В частности, вы не можете:

struct Foo {
    Foo foo;
}

(или что-нибудь еще, что приведет к круговому размеру) - компилятор отвечает:

Элемент Struct 'Foo.foo' типа 'Foo' вызывает цикл в структуре структуры

Однако во всех остальных случаях это нормально; с вопросом инициализации, я бы сказал: просто оставьте его неназначенным изначально и позвольте вызывающему абоненту присваивать значение через свойство.

Ответ 4

Да, вы можете иметь Employee внутри Employee и не вызвать бесконечный цикл, по умолчанию Manager свойство объекта Employee будет null.

Ответ 5

Это работает, вы можете просто попробовать s.th. как:

public class A
{
    public A test { get; set; }
}

Ответ 6

В частности, вопрос о конструкции (я ответил + I'd Odeds) - как вы говорите, создание экземпляра в конструкторе - плохой ход.

Но тогда спросите себя - зачем вам когда-либо понадобиться. В вашем случае Manager/Employee вы не всегда можете быть уверены, что у сотрудника всегда есть менеджер, а если нет, вы не должны использовать пустой экземпляр new ed, чтобы обозначить это, но null.

Когда ваш тип будет иметь общедоступные атрибуты get/set в свойствах, обычно вы, вероятно, загружаете эти деревья объектов из какого-то внешнего источника, и в этом случае вам не о чем беспокоиться. В равной степени вы можете иметь конструктор, который принимает другие экземпляры Employee для отношений между менеджером и сотрудником и т.д.

Кроме того, вы должны также проверять круговые отношения в этом конструкторе, т.е. сотрудник не может быть кем-то менеджером и его сотрудником - попробуйте пройти родительское отношение child- > для этого и посмотреть, закончится ли это когда-либо!

Ответ 7

Во-первых, ответ Да у объекта может быть поле, содержащее сам экземпляр. Он может даже иметь методы, которые принимают или возвращают экземпляры одного и того же класса, и могут даже зависеть от себя в определении класса, например:

public class Person : IComparable<Person> //legal, recursive definition
{
   //fields (or properties) that are of type Person
   public Person Father;
   public Person Mother;
   public List<Person> Children;

   // method that takes a Person as a parameter
   public bool IsParent(Person potentialParent)
   {
      ....
   }

   //method that returs a Person
   public Person Clone()
   {
      //TODO: real implementation coming soon
   }

   public Person(){}

   //constructor that takes persons as arguments
   public Person(Person father, Person Mother)
   {
      Father = father;
      Mother = mother;
   }
}

По умолчанию все ссылочные значения null 'd, поэтому у вас не будет проблемы с конструктором, если вы не создадите ее самостоятельно. Итак, Да, могут возникать проблемы с циклическими ссылками и бесконечными циклами (у каждого родителя есть дети, у которых есть родители с родителями и т.д.), Но обычно они могут быть обнаружены и исключены тривиально.

Единственные случаи, с которыми я столкнулся с такими проблемами, - это когда я использовал XML (или другую текстовую) сериализацию на объектах с циркулярной ссылкой.

Ответ 8

Я пробовал этот путь, и это сработало для меня:

class Program
{
    static void Main(string[] args)
    {
        A a = new A(new A());
    }
}

public class A
{
    public string Name { get; set; }
    public A a;

    public A() { }
    public A(A _a)
    {
        a = _a;
    }
}

Теперь вы можете использовать его в функции Main(), например:

class Program
{
    static void Main(string[] args)
    {
        A a = new A(new A());
        a.Name = "Roger";
        a.a.Name = "John";
        Console.WriteLine("{0}, {1}", a.Name, a.a.Name);
    }
}