家庭和人民的代表

Mic*_*ler 1 c# data-structures

在C++中,我可以做这样的事情

class Person
{
    House * myhouse;
}

class House
{
    std::vector<Person*> members;
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能在C#中做类似的事情?

Sal*_*iti 6

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这里没有字段,而是使用属性,特别是自动属性.这既是为了更清洁,又是将外部世界暴露给外部世界通常不如暴露属性,还因为我可以通过这种方式控制人们如何访问属性以进行读取和写入.在这个例子中,属性成员是公共的读取,但私有的写入,我在构造函数中初始化它.

在C#中,没有在堆栈中分配的对象的概念,对象总是在堆中分配.

这意味着类总是引用类型,List类型的变量是对List类型的对象的引用,就像指针在C++中一样.因此,您需要使用new运算符来分配它,否则默认值将为null.

当然,正如您所知,在C#中有垃圾收集器,因此您不需要删除该对象.

在C#中也有值类型,基本类型如int,float,double和struct是值类型,它们确实以不同的方式工作.

数组和字符串仍然是引用类型(类).

另请注意,在C#类字段中,默认情况下在构造函数中初始化为0,您可以想到的每个类型都将初始化为0,因此,指针将为null,float将为0.0f,struct将为struct将所有字段设置为0.就像C中的calloc一样.

然而,可能存在另一种完全不同的方法.我们可以使用基类Collection并使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 && 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();
        }
    }
Run Code Online (Sandbox Code Playgroud)