简体   繁体   中英

C# struct with object as data member

As we know, in C# structs are passed by value, not by reference. 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? 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. The third type is a primitive, so it's also copied. But what about the dm_strMessage, which is a reference to an object? When it's copied, another reference to the same String is created, right? 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. 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. The MSDN documentation says that System.String is thread safe. 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? I'm trying to figure out if my MessageBox struct has any potential flaws / pitfalls being a structure vs. a class. Thanks for any input.

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.

It probably should not be a struct. See the guidelines on MSDN for choosing between a class and a struct .

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.
  • 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.

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
  • 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. 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.

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. For example, it's not safe to share a List<T> between multiple threads which are potentially going to modify the list.

From a GC perspective, passing a single struct is not much different to passing the fields as individual parameters. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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