家庭和人民的代表

发布于 2024-12-14 12:42:23 字数 171 浏览 1 评论 0原文

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

class Person
{
    House * myhouse;
}

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

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

In C++ I could do something like this

class Person
{
    House * myhouse;
}

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

How can I do a similar thing in C#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尽揽少女心 2024-12-21 12:42:23
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。就像 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();
        }
    }
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>();
    }
}

Instead of fields here i'm using properties, in particular, automatic properties.
This is both for being cleaner, exposing a field to the outer world is usually less clean than exposing a property, and also because i can control in this way how people can access to the properties for read and for write. In this example, property Members is public for read but private for write, I initialize it in the constructor.

In C# there is not the concept of objects allocated in stack, objects are always allocated in heap.

This means classes are always reference types and a variable of type List is a reference to an object of type List, like a pointer is in C++.
For this reason you need to use the new operator to allocate it, or the default value will be null.

Of course, as you know, in C# there is the garbage collector, so you don't need to delete the object.

In C# there are also value types, basic types like int, float, double and struct are value types, and they works in a different way indeed.

Arrays and strings are still reference types (classes).

Also note that in C# class fields are initialized by default in the constructor to 0, each type you can think of will be initialized with 0, so, a pointer will be null, a float will be 0.0f, a struct will be a struct with all fields set to 0. Like a calloc in C.

There is however another totally different approach possible.
We can use the base class Collection and make the MyHouse property totally transparent and safe: we set it when we change the collection, this technique is used often.

    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();
        }
    }
萌︼了一个春 2024-12-21 12:42:23
class Person
{
    House myhouse;
}

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

class House
{
    List<Person> members = new List<Person>;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文