在这里的SO讨论之后,我已经多次看到这样的评论,即可变结构体是“邪恶的”(就像在这个问题的答案中)。
c#中的可变性和结构的实际问题是什么?
在这里的SO讨论之后,我已经多次看到这样的评论,即可变结构体是“邪恶的”(就像在这个问题的答案中)。
c#中的可变性和结构的实际问题是什么?
当前回答
假设您有一个包含1,000,000个结构体的数组。每个结构体都用bid_price、offer_price(可能是小数)等表示权益,这是由c# /VB创建的。
假设数组是在非托管堆中分配的内存块中创建的,以便其他一些本地代码线程能够并发地访问该数组(可能是一些高性能代码进行数学运算)。
想象一下c# /VB代码正在监听价格变化的市场反馈,该代码可能必须访问数组的某些元素(用于任何安全性),然后修改一些价格字段。
想象一下,这个过程以每秒数万次甚至数十万次的速度进行。
让我们面对现实吧,在这种情况下,我们确实希望这些结构体是可变的,它们必须是可变的,因为它们被其他本地代码共享所以创建副本是没有用的;他们需要这样做,因为以这样的速率复制大约120字节的结构是疯狂的,特别是当一个更新实际上可能只影响一两个字节时。
Hugo
其他回答
它与结构无关(也与c#无关),但在Java中,当可变对象是哈希映射中的键时,你可能会遇到问题。如果你在将它们添加到映射后更改它们,它也更改了哈希代码,可能会发生糟糕的事情。
从哪里开始;-p
埃里克·利珀特的博客总是很适合引用:
这是可变的另一个原因 值类型是邪恶的。试着总是 使值类型不可变。
首先,您很容易丢失更改……例如,从列表中获取内容:
Foo foo = list[0];
foo.Name = "abc";
这改变了什么?没有什么有用的…
属性也是一样:
myObj.SomeProperty.Size = 22; // the compiler spots this one
强迫你做:
Bar bar = myObj.SomeProperty;
bar.Size = 22;
myObj.SomeProperty = bar;
不那么关键的是规模问题;可变对象往往有多个属性;然而,如果你有一个包含两个int型,一个string型,一个DateTime型和一个bool型的结构体,你会很快消耗大量内存。使用类,多个调用方可以共享对同一个实例的引用(引用很小)。
可变结构体并不邪恶。
在高绩效环境下,它们是绝对必要的。例如,当缓存线和垃圾收集成为瓶颈时。
我不认为在这些完全有效的用例中使用不可变结构体是“邪恶的”。
我可以看到c#的语法没有帮助区分值类型或引用类型的成员的访问,所以我完全赞成使用强制不变性的不可变结构,而不是可变结构。
然而,与其简单地给不可变结构贴上“邪恶”的标签,我建议接受这种语言,提倡更有帮助和建设性的经验法则。
例如:"struct是默认复制的值类型。如果你不想复制他们,你需要一份推荐信。 “首先尝试使用只读结构体”。
如果你坚持结构体的用途(在c#、Visual Basic 6、Pascal/Delphi、c++结构类型(或类)中,当它们不用作指针时),你会发现结构体只不过是一个复合变量。这意味着:您将把它们视为一个通用名称(您引用成员的记录变量)下的一组变量。
我知道这会让很多习惯于面向对象编程的人感到困惑,但如果使用得当,这并不是说这些东西本质上是邪恶的理由。有些结构按照它们的意图是不可变的(Python的namedtuple就是这种情况),但这是另一种需要考虑的范例。
是的:结构体涉及大量内存,但它不会精确地通过执行以下操作来增加内存:
point.x = point.x + 1
相比:
point = Point(point.x + 1, point.y)
在不可变的情况下,内存消耗至少是相同的,甚至更多(尽管这种情况对于当前堆栈来说是临时的,这取决于语言)。
But, finally, structures are structures, not objects. In POO, the main property of an object is their identity, which most of the times is not more than its memory address. Struct stands for data structure (not a proper object, and so they don't have identity anyhow), and data can be modified. In other languages, record (instead of struct, as is the case for Pascal) is the word and holds the same purpose: just a data record variable, intended to be read from files, modified, and dumped into files (that is the main use and, in many languages, you can even define data alignment in the record, while that's not necessarily the case for properly called Objects).
Want a good example? Structs are used to read files easily. Python has this library because, since it is object-oriented and has no support for structs, it had to implement it in another way, which is somewhat ugly. Languages implementing structs have that feature... built-in. Try reading a bitmap header with an appropriate struct in languages like Pascal or C. It will be easy (if the struct is properly built and aligned; in Pascal you would not use a record-based access but functions to read arbitrary binary data). So, for files and direct (local) memory access, structs are better than objects. As for today, we're used to JSON and XML, and so we forget the use of binary files (and as a side effect, the use of structs). But yes: they exist, and have a purpose.
他们并不邪恶。只要把它们用在正确的地方。
如果你从锤子的角度思考,你会想把螺丝当作钉子,发现螺丝更难扎进墙里,这将是螺丝的错,它们将是邪恶的。
结构是值类型,这意味着它们在传递时被复制。
所以如果你改变了一份副本,你只是改变了那份副本,而不是原件,也不是周围可能存在的其他副本。
如果你的struct是不可变的,那么所有通过值传递的自动副本都是相同的。
如果你想要改变它,你必须有意识地用修改过的数据创建一个结构的新实例。(非副本)