简体   繁体   English

C#struct将object作为数据成员

[英]C# struct with object as data member

As we know, in C# structs are passed by value, not by reference. 我们知道,在C#中,结构是按值传递的,而不是通过引用传递的。 So if I have a struct with the following data members: 所以,如果我有一个包含以下数据成员的结构:

private struct MessageBox
{
    // data members
    private DateTime dm_DateTimeStamp; // a struct type
    private TimeSpan dm_TimeSpanInterval; // also a struct
    private ulong dm_MessageID; // System.Int64 type, struct
    private String dm_strMessage; // an object (hence a reference is stored here)
    // more methods, properties, etc ...
}

So when a MessageBox is passed as a parameter, a COPY is made on the stack, right? 因此,当MessageBox作为参数传递时,堆栈上会产生COPY,对吗? What does that mean in terms of how the data members are copied? 这对数据成员的复制方式意味着什么? The first two are struct types, so copies should be made of DateTime and TimeSpan. 前两个是结构类型,因此副本应该由DateTime和TimeSpan组成。 The third type is a primitive, so it's also copied. 第三种类型是基元,因此它也被复制。 But what about the dm_strMessage, which is a reference to an object? 但是dm_strMessage呢,它是对象的引用? When it's copied, another reference to the same String is created, right? 当它被复制时,会创建对同一个String的另一个引用,对吧? The object itself resides in the heap, and is NOT copied (there is only one instance of it on the heap.) So now we have to references to the same object of type String. 对象本身驻留在堆中,并且不被复制(堆上只有一个实例。)所以现在我们必须引用String类型的同一对象。 If the two references are accessed from different threads, it's conceivable that the String object could be corrupted by being modified from two different directions simultaneously. 如果从不同的线程访问这两个引用,则可以想象String对象可能会被同时从两个不同的方向修改而被破坏。 The MSDN documentation says that System.String is thread safe. MSDN文档说System.String是线程安全的。 Does that mean that the String class has a built-in mechanism to prevent an object being corrupted in exactly the type of situation described here? 这是否意味着String类有一个内置机制来防止对象在这里描述的情况类型中被破坏? I'm trying to figure out if my MessageBox struct has any potential flaws / pitfalls being a structure vs. a class. 我试图弄清楚我的MessageBox结构是否有任何潜在的缺陷/缺陷是结构与类。 Thanks for any input. 感谢您的任何意见。

Source.Energy. Source.Energy。

Strings cannot be "corrupted" by multithreaded access because they are immutable. 字符串不能被多线程访问“损坏”,因为它们是不可变的。

You should avoid making your structs mutable though. 你应该避免使你的结构变得可变。 Read this question and answers for more information. 阅读此问题和答案以获取更多信息。

I'm trying to figure out if my MessageBox struct has any potential flaws / pitfalls being a structure vs. a class. 我试图弄清楚我的MessageBox结构是否有任何潜在的缺陷/缺陷是结构与类。

It probably should not be a struct. 它可能不应该是一个结构。 See the guidelines on MSDN for choosing between a class and a struct . 有关在类和结构之间进行选择的信息,请参阅MSDN上的指南。

Do not define a structure unless the type has all of the following characteristics: 除非类型具有以下所有特征,否则不要定义结构:

  • It logically represents a single value, similar to primitive types (integer, double, and so on). 它逻辑上表示单个值,类似于基本类型(整数,双精度等)。
  • It has an instance size smaller than 16 bytes. 它的实例大小小于16个字节。
  • It is immutable. 这是不可改变的。
  • It will not have to be boxed frequently. 它不必经常装箱。

I think your MessageBox definitely breaks the first and second guidelines, and possibly also the third depending on what methods are available. 我认为你的MessageBox肯定会违反第一和第二条准则,也可能是第三条准则,具体取决于可用的方法。

Firstly, your first sentence implies that you think classes are passed by reference. 首先,你的第一句话意味着你认为课程是通过引用传递的。 This isn't the case - the reference is passed by value (by default). 情况并非如此 - 引用按值传递(默认情况下)。 See my article on parameter passing for more details. 有关详细信息,请参阅有关参数传递的文章 When you understand this, it may make other aspects clearer. 当你理解这一点时,它可能会使其他方面更加清晰。

Your question is really about two different things: 你的问题实际上是两件事:

  • How struct values are copied 如何复制struct值
  • How safe it is to share strings between threads 在线程之间共享字符串是多么安全

I think it will help you if you separate the two. 我认为如果你将两者分开,它会对你有所帮助。

When copying the value of a struct, the members are treated the same way whether they're value types or reference types. 复制结构的值时,无论它们是值类型还是引用类型,都会以相同的方式处理成员。 The value is simply copied, bit for bit. 简单地复制该值,一点一点地进行。 The important thing to understand is that the value of dm_strMessage is a reference, not a string object. 需要了解的重要一点是, dm_strMessage的值是引用,而不是字符串对象。 That reference is copied. 该引用被复制。

This is no more harmful than this code: 这并不比这段代码更有害:

string message = GetMessageFromSomewhere();
string otherMessage = message;

Exactly the same thing happens: the value of message is copied into otherMessage : the two variables have the same value, which is a reference to a single string object. 完全相同的事情发生了: message的值被复制到otherMessage :两个变量具有相同的值,这是对单个字符串对象的引用。

So far, this has nothing to do with threading. 到目前为止,这与线程无关。 Now if you share a string reference between multiple threads, that's safe - because strings are immutable . 现在如果你在多个线程之间共享一个字符串引用,这是安全的 - 因为字符串是不可变的 You can't change the contents of a string object, so two strings can perfectly happily read data from the same object with no risks of corruption. 您无法更改字符串对象的内容,因此两个字符串可以非常愉快地从同一对象中读取数据而不会有损坏的风险。 The same is not true of many other types in .NET. 同样是没有太多的其他类型的.NET的真实。 For example, it's not safe to share a List<T> between multiple threads which are potentially going to modify the list. 例如,在可能要修改列表的多个线程之间共享List<T>是不安全的。

From a GC perspective, passing a single struct is not much different to passing the fields as individual parameters. 从GC的角度来看,传递单个结构与将字段作为单个参数传递没有太大区别。 There's certainly nothing to concern yourself with when passing a string in a struct, vs. passing a string as a simple parameter. 在结构中传递字符串时,与传递字符串作为简单参数无关。

Strings are immutable, so they are impossible to corrupt, no matter how many threads share them. 字符串是不可变的,因此无论有多少线程共享它们,它们都不可能被破坏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM