C#:一般首选哪种类型的数据容器?
当创建一个简单的数据容器类时,它应该是什么?
- 类还是结构?
- 可变还是不可变?
- 有或没有非空构造函数?
上述示例:
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;
}
}
我们有什么充分理由选择其中一个? 或者主要是主观偏好将它们分开? 或者它在很大程度上取决于特定的用例? 如果是这样,在什么用例中您应该选择什么以及为什么?
When creating a simple data container class, what should it be?
- Class or struct?
- Mutable or immutable?
- With or without non-empty constructor?
Examples of the above:
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;
}
}
Any good reasons we should choose one above another? Or are there mostly subjective preferences that separate them? Or does it depend a lot on the spesific use cases? If so in what use cases should you choose what and why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
几乎总是一个班级; 结构实际上应该仅用于是值的事物 - 例如,复数或货币类型/值对 - 并且应该几乎 - 不排除不可变的。
如果要进行数据绑定,无参数构造函数对于可变数据非常方便,因为这允许系统创建实例而无需您自己添加额外代码。 非空构造函数对于不可变数据非常重要。 对于可变数据,对象初始值设定项在这方面大有帮助(尽管在验证等方面不太相同):
您的类型是否不可变取决于您; 可变使得数据绑定和序列化变得更容易。 一般来说,您往往会在 .NET 中看到更多可变类型,但随着我们进入并行/众核时代,这种情况可能会发生变化。
Almost always a class; structs should really only be used for things that are values - for example, a complex-number, or a currency type/value pair - and should almost-without-exclusion be immutable.
A parameterless constructor is handy on mutable data if you are going to do data-binding, as this allows the system to create instances without additional code from yourself. A non-empty constructor is pretty-much essential for immutable data. For mutable data, an object initializer goes a long way towards that (although isn't quite the same in terms of validation etc):
Whether your types are immutable is up to you; mutable makes it easier to do data-binding and serialization. In general, you tend to see more mutable types in .NET, but this may change as we get into the parallel / many-core era.
您几乎应该总是更喜欢类而不是结构。 仅当对象表示(不可变)值时才使用结构。
如果您需要更改对象并且这样做是安全的,则将其设置为可变的,否则将其设置为不可变并使用克隆。
如果您需要更改对象并且这样
如果使用默认构造函数创建对象时该对象处于有效状态,那就没问题。 否则,请始终提供您自己的构造函数。
You should almost always prefer classes over structs. Use structs only when the object represents an (immutable) value.
If you need to change the object and it is safe to do so then make it mutable, else make it immutable and use cloning.
If the object is in a valid state when created with the default constructor, fine. Otherwise always provide your own constructor.
仅当需要值类型语义时才使用结构,并尝试完全避免可变结构。
除此之外,我认为这取决于个人或团队的偏好和您的特定要求。
(这些天我尝试尽可能使用不可变对象,这几乎总是需要将值传递到构造函数中。)
Only use structs when you need value-type semantics, and try to avoid mutable structs completely.
Other than that, I think it comes down to personal, or team, preference and your particular requirements.
(These days I'm trying to use immutable objects whenever possible, which almost always necessitates passing values into the constructor.)
关于类与结构的几点:
类是按引用传递的,这意味着相同的实例对象在函数之间传递。 如果在方法 A 中创建 MyClass 并调用方法 B,方法 B 会更改该类并且不会向方法 A 返回任何内容,方法 A 会看到 MyClass 中所做的更改,因为它们引用同一个对象。 引用通常是 int32,因此无论您的类有多大,调用方法 B 都会很快,因为它只传递 4 个字节。 类依靠垃圾收集器来决定何时不再使用它(传递类的开销较小,但会增加垃圾收集器的开销)。
结构是按值传递(或值类型)。 这意味着在传递时整个结构都会被复制。 如果您的结构很大,这将需要很长时间。 方法 B 中对结构的更改不会在方法 A 中显示,除非它被返回(再次花费时间,因为它是按值传递的),并且方法 A 读取返回值。 结构体是在堆栈上创建的,并且没有垃圾收集开销(如果您检查 IL 代码,您可以看到这一点)。
与类相比,结构有许多限制,例如缺乏虚拟方法和其他多态功能。
最好支持类,除非您要在同一方法中快速创建和丢弃大量对象(由于垃圾收集而耗尽系统资源),在这种情况下支持结构。
A couple of points on classes vs structs:
Classes are pass-by-reference which means that the same instance object is passed between functions. If you create MyClass in method A and call method B, method B changes the class and returns nothing to method A, method A sees the changes made in MyClass because they are refering to the same object. A reference is usually an int32, so no matter how big your class is it will be quick to call method B because it's only passing 4 bytes. Classes rely on the Garbage Collector to decide when it is no longer being used (smaller overhead in passing the class around but adds overhead to the garbage collector).
Structs are pass-by-value (or a value type). This means that the whole struct is copied when it is passed around. If your struct is big, this will take a long time. A change to the struct in Method B won’t show in method A unless it is returned (again costing time as it is pass by value), and Method A reads the return value. Structs are created on the stack and do not have a garbage collection overhead (you can see this if you examine your IL code).
There are many limitations in structs compared to classes, such as the lack of virtual methods and other polymorphic functionality.
It's best to favour classes, unless you are going to rapidly create and discard lots of objects in the same method (which drain system resources due to garbage collection), in which case favour structs.
我通常使用不可变的类,并通过构造函数设置/传递所有值。
I usually do immutable classes with all the values being set/passed in via the constructor.
此外,根据经验,结构体不应大于 16 个字节(处理器缓存行的大小)。
Also, there's the rule of thumb that structs shouldn't be larger than 16 bytes - the size of a processor cache line.
每当您需要提供对象“功能”而不仅仅是身份或状态(即“值”)时,请考虑使用类。
如前所述,结构是值类型,因此无论您在何处使用它们,都会复制它们。 此外,实例化类与结构时的性能差异可以忽略不计。
Consider using classes whenever you need to provide object "functionality" as opposed to merely identity or state i.e. "values".
As has already been stated, structs are value types and as such will be copied wherever you use them. Also, there is a negligible performance difference when instantiating classes versus structs.
看起来几乎所有时候结构都对类的易用性和效率造成了不必要的干扰。
It really seems like almost all of the time structs are an unnecessary distraction from the ease and efficiency of classes.