C#:一般来说,首选哪种数据容器?

时间:2009-07-13 11:46:22

标签: c# data-structures data-containers

创建一个简单的数据容器类时,应该是什么?

  • 类或结构?
  • 可变或不可变?
  • 是否有非空构造函数?

上述例子:

struct MutableStruct
{
    public string Text { get; set; }
    public int Number { get; set; }
}

struct ImmutableStruct
{
    public string Text { get; private set; }
    public int Number { get; private set; }
    public ImmutableStruct(string text, int number)
        : this()
    {
        Text = text;
        Number = number;
    }
}

struct MutableStructWithConstructor
{
    public string Text { get; set; }
    public int Number { get; set; }
    public MutableStructWithConstructor(string text, int number)
        : this()
    {
        Text = text;
        Number = number;
    }
}
class MutableClass
{
    public string Text { get; set; }
    public int Number { get; set; }
}

class ImmutableClass
{
    public string Text { get; private set; }
    public int Number { get; private set; }
    public ImmutableClass(string text, int number)
    {
        Text = text;
        Number = number;
    }
}

class MutableClassWithConstructor
{
    public string Text { get; set; }
    public int Number { get; set; }
    public MutableClassWithConstructor(string text, int number)
    {
        Text = text;
        Number = number;
    }
}

我们应该选择一个高于另一个的好理由吗?或者主要是将主观偏好分开?或者它在很大程度上依赖于特定用例?如果是这样,在哪些用例中你应该选择什么和为什么?

8 个答案:

答案 0 :(得分:11)

几乎总是一堂课;结构应该只用于是值的东西 - 例如,复数 - 或货币类型/值对 - 并且应该几乎 - 不包括 - 排除不可变的。

如果要进行数据绑定,无参数构造函数对于可变数据很方便,因为这允许系统在没有自己的附加代码的情况下创建实例。非空构造函数对于不可变数据非常重要。对于可变数据,对象初始值设定项有很长的路要走(尽管在验证方面不是相当相同):

var obj = new Person {Name="Fred", DateOfBirth=DateTime.Today};

您的类型是否不可变取决于您; mutable使得更容易进行数据绑定和序列化。一般来说,您往往会在.NET中看到更多可变类型,但随着我们进入并行/多核时代,这可能会发生变化。

答案 1 :(得分:3)

  • 你几乎总是喜欢类而不是结构。仅当对象表示(不可变)值时才使用结构。

  • 如果您需要更改对象并且这样做是安全的,那么使其变为可变,否则使其变为不可变并使用克隆。

  • 如果使用默认构造函数创建对象时处于有效状态,则很好。否则总是提供自己的构造函数。

答案 2 :(得分:2)

只在需要值类型语义时才使用结构,并尝试完全避免可变结构。

除此之外,我认为这取决于个人,团队,偏好以及您的特殊要求。

(这些天我试图尽可能使用不可变对象,这几乎总是需要将值传递给构造函数。)

答案 3 :(得分:1)

关于类与结构的几点:

类是传递引用,这意味着在函数之间传递相同的实例对象。如果在方法A中创建MyClass并调用方法B,则方法B更改类并且不向方法A返回任何内容,方法A查看在MyClass中所做的更改,因为它们引用了同一个对象。引用通常是一个int32,所以无论你的类有多大,它都会很快调用方法B,因为它只传递4个字节。类依赖于垃圾收集器来决定何时不再使用它(传递类的开销较小,但会增加垃圾收集器的开销)。

结构是值传递(或值类型)。这意味着整个结构在传递时会被复制。如果您的结构很大,这将需要很长时间。方法B中对结构的更改将不会在方法A中显示,除非它被返回(再次按值传递计算时间),并且方法A读取返回值。结构是在堆栈上创建的,没有垃圾收集开销(如果检查IL代码,可以看到这一点)。

与类相比,结构中存在许多限制,例如缺少虚方法和其他多态功能。

最好支持类,除非你要在同一个方法中快速创建和丢弃大量对象(由于垃圾收集导致系统资源耗尽),在这种情况下有利于结构。

答案 4 :(得分:0)

我通常使用构造函数设置/传入所有值来创建不可变类。

答案 5 :(得分:0)

此外,根据经验,结构不应大于16个字节 - 处理器缓存行的大小。

答案 6 :(得分:0)

考虑在需要提供对象“功能”时使用类,而不仅仅是身份或状态,即“值”。

正如已经说过的,结构是值类型,因此将在您使用它们的任何地方进行复制。此外,在实例化类与结构体时,性能差异可以忽略不计。

答案 7 :(得分:0)

看起来几乎所有时间结构都不必分散课程的简易性和效率。