c# - structs - When to use struct?




when to use struct vs class swift (19)

When should you use struct and not class in C#? My conceptual model is that structs are used in times when the item is merely a collection of value types. A way to logically hold them all together into a cohesive whole.

I came across these rules here:

  • A struct should represent a single value.
  • A struct should have a memory footprint less than 16 bytes.
  • A struct should not be changed after creation.

Do these rules work? What does a struct mean semantically?


.NET supports value types and reference types (in Java, you can define only reference types). Instances of reference types get allocated in the managed heap and are garbage collected when there are no outstanding references to them. Instances of value types, on the other hand, are allocated in the stack, and hence allocated memory is reclaimed as soon as their scope ends. And of course, value types get passed by value, and reference types by reference. All C# primitive data types, except for System.String, are value types.

When to use struct over class,

In C#, structs are value types, classes are reference types. You can create value types, in C#, using the enum keyword and the struct keyword. Using a value type instead of a reference type will result in fewer objects on the managed heap, which results in lesser load on the garbage collector (GC), less frequent GC cycles, and consequently better performance. However, value types have their downsides too. Passing around a big struct is definitely costlier than passing a reference, that's one obvious problem. The other problem is the overhead associated with boxing/unboxing. In case you're wondering what boxing/unboxing mean, follow these links for a good explanation on boxing and unboxing. Apart from performance, there are times when you simply need types to have value semantics, which would be very difficult (or ugly) to implement if reference types are all you have. You should use value types only, When you need copy semantics or need automatic initialization, normally in arrays of these types.


A struct is a value type. If you assign a struct to a new variable, the new variable will contain a copy of the original.

public struct IntStruct {
    public int Value {get; set;}
}

Excecution of the following results in 5 instances of the struct stored in memory:

var struct1 = new IntStruct() { Value = 0 }; // original
var struct2 = struct1;  // A copy is made
var struct3 = struct2;  // A copy is made
var struct4 = struct3;  // A copy is made
var struct5 = struct4;  // A copy is made

// NOTE: A "copy" will occur when you pass a struct into a method parameter.
// To avoid the "copy", use the ref keyword.

// Although structs are designed to use less system resources
// than classes.  If used incorrectly, they could use significantly more.

A class is a reference type. When you assign a class to a new variable, the variable contains a reference to the original class object.

public class IntClass {
    public int Value {get; set;}
}

Excecution of the following results in only one instance of the class object in memory.

var class1 = new IntClass() { Value = 0 };
var class2 = class1;  // A reference is made to class1
var class3 = class2;  // A reference is made to class1
var class4 = class3;  // A reference is made to class1
var class5 = class4;  // A reference is made to class1  

Structs may increase the likelihood of a code mistake. If a value object is treated like a mutable reference object, a developer may be surprised when changes made are unexpectedly lost.

var struct1 = new IntStruct() { Value = 0 };
var struct2 = struct1;
struct2.Value = 1;
// At this point, a developer may be surprised when 
// struct1.Value is 0 and not 1

Briefly, use struct if :

1- your object properties/fields do not need to be changed. I mean you just want to give them an initial value and then read them.

2- properties and fields in your object are value type and they are not so large.

If that's the case you can take advantage of structs for a better performance and optimized memory allocation as they use only stacks rather than both stacks and heaps (in classes)


First: Interop scenarios or when you need to specify the memory layout

Second: When the data is almost the same size as a reference pointer anyway.


Here is a basic rule.

  • If all member fields are value types create a struct.

  • If any one member field is a reference type, create a class. This is because the reference type field will need the heap allocation anyway.

Exmaples

public struct MyPoint 
{
    public int X; // Value Type
    public int Y; // Value Type
}

public class MyPointWithName 
{
    public int X; // Value Type
    public int Y; // Value Type
    public string Name; // Reference Type
}

I do not agree with the rules given in the original post. Here are my rules:

1) You use structs for performance when stored in arrays. (see also When are structs the answer?)

2) You need them in code passing structured data to/from C/C++

3) Do not use structs unless you need them:

  • They behave different from "normal objects" (reference types) under assignment and when passing as arguments, which can lead to unexpected behavior; this is particularly dangerous if the person looking at the code does not know they are dealing with a struct.
  • They cannot be inherited.
  • Passing structs as arguments is more expensive than classes.

I rarely use a struct for things. But that's just me. It depends whether I need the object to be nullable or not.

As stated in other answers, I use classes for real-world objects. I also have the mindset of structs are used for storing small amounts of data.


I think a good first approximation is "never".

I think a good second approximation is "never".

If you are desperate for perf, consider them, but then always measure.


I was just dealing with Windows Communication Foundation [WCF] Named Pipe and I did notice that it does make sense to use Structs in order to ensure that exchange of data is of value type instead of reference type.


In addition to the "it is a value" answer, one specific scenario for using structs is when you know that you have a set of data that is causing garbage collection issues, and you have lots of objects. For example, a large list/array of Person instances. The natural metaphor here is a class, but if you have large number of long-lived Person instance, they can end up clogging GEN-2 and causing GC stalls. If the scenario warrants it, one potential approach here is to use an array (not list) of Person structs, i.e. Person[]. Now, instead of having millions of objects in GEN-2, you have a single chunk on the LOH (I'm assuming no strings etc here - i.e. a pure value without any references). This has very little GC impact.

Working with this data is awkward, as the data is probably over-sized for a struct, and you don't want to copy fat values all the time. However, accessing it directly in an array does not copy the struct - it is in-place (contrast to a list indexer, which does copy). This means lots of work with indexes:

int index = ...
int id = peopleArray[index].Id;

Note that keeping the values themselves immutable will help here. For more complex logic, use a method with a by-ref parameter:

void Foo(ref Person person) {...}
...
Foo(ref peopleArray[index]);

Again, this is in-place - we have not copied the value.

In very specific scenarios, this tactic can be very successful; however, it is a fairly advanced scernario that should be attempted only if you know what you are doing and why. The default here would be a class.


My rule is

1, Always use class;

2, If there is any performance issue, I try to change some class to struct depending on the rules which @IAbstract mentioned, and then do a test to see if these changes can improve performance.


Nah - I don't entirely agree with the rules. They are good guidelines to consider with performance and standardization, but not in light of the possibilities.

As you can see in the responses, there are a log of creative ways to use them. So, these guidelines need to just be that, always for the sake of performance and efficiency.

In this case, I use classes to represent real world objects in their larger form, I use structs to represent smaller objects that have more exact uses. The way you said it, "a more cohesive whole." The keyword being cohesive. The classes will be more object oriented elements, while structs can have some of those characteristics, their on a smaller scale. IMO.

I use them a lot putting in Treeview and Listview tags where common static attributes can be accessed very quickly. I would struggle to get this info another way. For example, in my database applications, I use a Treeview where I have Tables, SPs, Functions, or any other objects. I create and populate my struct, put it in the tag, pull it out, get the data of the selection and so forth. I wouldn't do this with a class!

I do try and keep them small, use them in single instance situations, and keep them from changing. It's prudent to be aware of memory, allocation, and performance. And testing is so necessary.


Structs are good for atomic representation of data, where the said data can be copied multiple times by the code. Cloning an object is in general more expensive than copying a struct, as it involves allocating the memory, running the constructor and deallocating/garbage collection when done with it.


Structure or value types can be used in following scenarios -

  1. If you want to prevent the object to be collected by garbage collection.
  2. If it is a simple type and no member function modifies its instance fields
  3. If there is no need to derive from other types or being derived to other types.

You can know more about the value types and values types here on this link


Structures are in most ways like classes/objects. Structure can contain functions, members and can be inherited. But structures are in C# used just for data holding. Structures does take less RAM than classes and are easier for garbage collector to collect. But when you use functions in your structure, then compiler actually takes that structure very similarly as class/object, so if you want something with functions, then use class/object.


The C# struct is a lightweight alternative to a class. It can do almost the same as a class, but it's less "expensive" to use a struct rather than a class. The reason for this is a bit technical, but to sum up, new instances of a class is placed on the heap, where newly instantiated structs are placed on the stack. Furthermore, you are not dealing with references to structs, like with classes, but instead you are working directly with the struct instance. This also means that when you pass a struct to a function, it is by value, instead of as a reference. There is more about this in the chapter about function parameters.

So, you should use structs when you wish to represent more simple data structures, and especially if you know that you will be instantiating lots of them. There are lots of examples in the .NET framework, where Microsoft has used structs instead of classes, for instance the Point, Rectangle and Color struct.


Use a struct when you want value semantics as opposed to reference semantics.

Edit

Not sure why folks are downvoting this but this is a valid point, and was made before the op clarified his question, and it is the most fundamental basic reason for a struct.

If you need reference semantics you need a class not a struct.


Whenever you don't need polymorphism, want value semantics, and want to avoid heap allocation and the associated garbage collection overhead. The caveat, however, is that structs (arbitrarily large) are more expensive to pass around than class references (usually one machine word), so classes could end up being faster in practice.


You need to use a "struct" in situations where you want to explicitly specify memory layout using the StructLayoutAttribute - typically for PInvoke.

Edit: Comment points out that you can use class or struct with StructLayoutAttribute and that is certainly true. In practice, you would typically use a struct - it is allocated on the stack vs the heap which makes sense if you are just passing an argument to an unmanaged method call.







struct