Reputation: 34770
In our application we have a Queue which is defined as the following:
private static Queue RawQ = new Queue();
Then two different types of objects are put onto the Queue, one are objects from a class (class A
) and one are objects from a struct (struct B
).
When we process the data from the Queue, we use typeof
to check the item from the Queue belongs to which type (class A or struct B).
My questions:
thanks,
Upvotes: 4
Views: 1025
Reputation: 4213
From the C# spec:
Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to type object or to an interface type that is implemented by the struct, a boxing operation takes place.
So, to answer 1) the queue contains boxed structs, not the actual struct values.
The answer to 2) falls out of that, a boxed struct and a reference have the same size in a queue's actual allocation.
For 3), I'd need more information. It would be preferable to have the same type in a queue and have polymorphic operations that are handled both by classes and structs in the appropriate ways. Excessive case statements and typeof() calls suggest that your program is more procedural than object-oriented. Maybe that's what you want, but C# is optimized for a OO approach.
Upvotes: 2
Reputation: 48949
1.for objects from class A, only their references are copied to the Queue and for object from struct B, their values are copied to the Queue, am I right?
That is correct. Except that value types would be boxed.
2.for a Queue, some items are references which is small and some items are values which are much bigger (about 408 Bytes). This will waste many memory space if the Queue is not small?
That is mostly correct. The boxing will add another 8 bytes (4 for the syncblock and 4 for the type information) so for large structs that is insignificant, but for smaller structs that would represent a larger ratio.
3.do you have a better way to do the same thing?
The best thing to do is convert that large struct into a class. There is no hard rule for knowing when to choose a struct or class based on size, but 32 bytes seems to be a common threshold. Of course, you could easily justify larger structs based on whether you really wanted value-type semantics, but 408 bytes is probably way beyond that threshold. If the type really needs value semantics you could make it an immutable class.
Another change you could make is to use the generic Queue class instead. Value types are not boxed as they would be with the normal Queue. However, you would still be copying that large struct even with the generic version.
Upvotes: 2
Reputation: 8190
I was trying to double check this, but here's what I belive happens:
The System.Collections.Queue class holds a collection of type Object
which is a reference type. Therefore, when you pass an instance of a Struct to your queue it gets boxed as an object. This creates a copy on the Heap, and provides a refernce pointer (which is what the Queue sees). So, the Queue itself does not get too big, but if you're doing a lot of these operations, you'll end up (according to Microsoft) with a memory and performance hit over the boxing/unboxing.
See the C# Language Specification for more.
Upvotes: 1
Reputation: 54734
for objects from class A, only their references are copied to the Queue and for object from struct B, their values are copied to the Queue, am I right?
Correct. Actually, when you add a struct B to the queue, it is boxed first. In other words, your B instance is copied onto the managed heap, and a reference to the copy is put on the queue.
for a Queue, some items are references which is small and some items are values which are much bigger (about 408 Bytes). This will waste many memory space if the Queue is not small?
Possibly - boxing the B instance takes a copy, which uses more memory than not taking a copy. It depends what happens to the original.
408 bytes is very large for a .NET struct; the general rule of thumb is that structs shouldn't be bigger than 16 bytes. The reason is similar to this: large structs introduce overhead due to copying and boxing.
do you have a better way to do the same thing?
I'd question whether B needs to be a struct in the first place. Another rule of thumb (mine, this time): you probably don't need ever need a struct in .NET code.
Upvotes: 3