Может ли пользовательский объект С# содержать свойство того же типа, что и сам?
Если я создал следующий 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);
}
}