Представление домохозяйств и людей

#c# #data-structures

#c# #структуры данных

Вопрос:

На C я мог бы сделать что-то вроде этого

 class Person
{
    House * myhouse;
}

class House
{
    std::vector<Person*> members;
}
  

Как я могу сделать аналогичную вещь в C #?

Ответ №1:

 public class Person
{
    public House MyHouse { get; set; }
}

public class House
{
    public List<Person> Members { get; private set; }

    public House()
    {
        this.Members = new List<Person>();
    }
}
  

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

В C # нет понятия объектов, размещаемых в стеке, объекты всегда размещаются в куче.

Это означает, что классы всегда являются ссылочными типами, а переменная типа List является ссылкой на объект типа List, как указатель в C . По этой причине вам необходимо использовать оператор new для его выделения, иначе значение по умолчанию будет равно null.

Конечно, как вы знаете, в C # есть сборщик мусора, поэтому вам не нужно удалять объект.

В C # также существуют типы значений, базовые типы, такие как int, float, double и struct, являются типами значений, и они действительно работают по-другому.

Массивы и строки по-прежнему являются ссылочными типами (классами).

Также обратите внимание, что в классе C # поля по умолчанию инициализируются в конструкторе значением 0, каждый тип, который вы можете придумать, будет инициализирован значением 0, поэтому указатель будет равен null, значение с плавающей точкой будет равно 0.0f, структура будет структурой со всеми полями, равными 0. Как calloc в C.

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

     public class Person
    {
        // This field is internal, it means that all classes in the same module (in the same dll for example) can access to this field.
        // This keyword was introduced for the same reason that the "friend" keyword exists in C  .
        // We need this internal so we can modify it from House class.
        internal House house;

        public House MyHouse
        {
            get { return this.house; }
        }
    }

    public class House :
        System.Collections.ObjectModel.Collection<Person>
    {
        // We shadow the base member, this is faster than default implementation, O(1).
        public new bool Contains(Person person)
        {
            return person != null amp;amp; person.house == this;
        }

        protected override void RemoveItem(int index)
        {
            Person person = this[index];
            base.RemoveItem(index);
            person.house = null;
        }

        protected override void SetItem(int index, Person item)
        {
            if (item == null)
                throw new ArgumentNullException("Person is null");
            if (item.house != null)
                throw new InvalidOperationException("Person already owned by another house");
            Person old = this[index];
            base.SetItem(index, item);
            old.house = null;
            item.house = this;
        }

        protected override void InsertItem(int index, Person item)
        {
            if (item == null)
                throw new ArgumentNullException("Person is null");
            if (item.house != null)
                throw new InvalidOperationException("Person already owned by another house");
            base.InsertItem(index, item);
            item.house = this;
        }

        protected override void ClearItems()
        {
            foreach (Person person in this)
            {
                person.house = null;
            }
            base.ClearItems();
        }
    }
  

Ответ №2:

 class Person
{
    House myhouse;
}

class House
{
    List<Person> members = new List<Person>;
}
  

Комментарии:

1. Вы никогда не инициализировали участников, вам нужно инициализировать это с помощью = new List<Person>(), это ведет себя иначе, чем C .