By Alex Baranosky


2009-02-06 17:37:55 8 Comments

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?

28 comments

@Roman Pokrovskij 2017-07-24 09:16:37

I made a small benchmark with BenchmarkDotNet to get a better understanding of "struct" benefit in numbers. I'm testing looping through array (or list) of structs (or classes). Creating those arrays or lists is out of the benchmark's scope - it is clear that "class" is more heavy will utilize more memory, and will involve GC.

So the conclusion is: be careful with LINQ and hidden structs boxing/unboxing and using structs for microoptimizations strictly stay with arrays.

P.S. Another benchmark about passing struct/class through call stack is there https://stackoverflow.com/a/47864451/506147

BenchmarkDotNet=v0.10.8, OS=Windows 10 Redstone 2 (10.0.15063)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233542 Hz, Resolution=309.2584 ns, Timer=TSC
  [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
  Clr    : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
  Core   : .NET Core 4.6.25211.01, 64bit RyuJIT


          Method |  Job | Runtime |      Mean |     Error |    StdDev |       Min |       Max |    Median | Rank |  Gen 0 | Allocated |
---------------- |----- |-------- |----------:|----------:|----------:|----------:|----------:|----------:|-----:|-------:|----------:|
   TestListClass |  Clr |     Clr |  5.599 us | 0.0408 us | 0.0382 us |  5.561 us |  5.689 us |  5.583 us |    3 |      - |       0 B |
  TestArrayClass |  Clr |     Clr |  2.024 us | 0.0102 us | 0.0096 us |  2.011 us |  2.043 us |  2.022 us |    2 |      - |       0 B |
  TestListStruct |  Clr |     Clr |  8.427 us | 0.1983 us | 0.2204 us |  8.101 us |  9.007 us |  8.374 us |    5 |      - |       0 B |
 TestArrayStruct |  Clr |     Clr |  1.539 us | 0.0295 us | 0.0276 us |  1.502 us |  1.577 us |  1.537 us |    1 |      - |       0 B |
   TestLinqClass |  Clr |     Clr | 13.117 us | 0.1007 us | 0.0892 us | 13.007 us | 13.301 us | 13.089 us |    7 | 0.0153 |      80 B |
  TestLinqStruct |  Clr |     Clr | 28.676 us | 0.1837 us | 0.1534 us | 28.441 us | 28.957 us | 28.660 us |    9 |      - |      96 B |
   TestListClass | Core |    Core |  5.747 us | 0.1147 us | 0.1275 us |  5.567 us |  5.945 us |  5.756 us |    4 |      - |       0 B |
  TestArrayClass | Core |    Core |  2.023 us | 0.0299 us | 0.0279 us |  1.990 us |  2.069 us |  2.013 us |    2 |      - |       0 B |
  TestListStruct | Core |    Core |  8.753 us | 0.1659 us | 0.1910 us |  8.498 us |  9.110 us |  8.670 us |    6 |      - |       0 B |
 TestArrayStruct | Core |    Core |  1.552 us | 0.0307 us | 0.0377 us |  1.496 us |  1.618 us |  1.552 us |    1 |      - |       0 B |
   TestLinqClass | Core |    Core | 14.286 us | 0.2430 us | 0.2273 us | 13.956 us | 14.678 us | 14.313 us |    8 | 0.0153 |      72 B |
  TestLinqStruct | Core |    Core | 30.121 us | 0.5941 us | 0.5835 us | 28.928 us | 30.909 us | 30.153 us |   10 |      - |      88 B |

Code:

[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
    [ClrJob, CoreJob]
    [HtmlExporter, MarkdownExporter]
    [MemoryDiagnoser]
    public class BenchmarkRef
    {
        public class C1
        {
            public string Text1;
            public string Text2;
            public string Text3;
        }

        public struct S1
        {
            public string Text1;
            public string Text2;
            public string Text3;
        }

        List<C1> testListClass = new List<C1>();
        List<S1> testListStruct = new List<S1>();
        C1[] testArrayClass;
        S1[] testArrayStruct;
        public BenchmarkRef()
        {
            for(int i=0;i<1000;i++)
            {
                testListClass.Add(new C1  { Text1= i.ToString(), Text2=null, Text3= i.ToString() });
                testListStruct.Add(new S1 { Text1 = i.ToString(), Text2 = null, Text3 = i.ToString() });
            }
            testArrayClass = testListClass.ToArray();
            testArrayStruct = testListStruct.ToArray();
        }

        [Benchmark]
        public int TestListClass()
        {
            var x = 0;
            foreach(var i in testListClass)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestArrayClass()
        {
            var x = 0;
            foreach (var i in testArrayClass)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestListStruct()
        {
            var x = 0;
            foreach (var i in testListStruct)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestArrayStruct()
        {
            var x = 0;
            foreach (var i in testArrayStruct)
            {
                x += i.Text1.Length + i.Text3.Length;
            }
            return x;
        }

        [Benchmark]
        public int TestLinqClass()
        {
            var x = testListClass.Select(i=> i.Text1.Length + i.Text3.Length).Sum();
            return x;
        }

        [Benchmark]
        public int TestLinqStruct()
        {
            var x = testListStruct.Select(i => i.Text1.Length + i.Text3.Length).Sum();
            return x;
        }
    }

@Marko Grdinic 2017-08-12 13:24:40

Have you figured out why structs are so much slower when used in lists and such? Is it because of the hidden boxing and unboxing that you've mentioned? If so why does it happen?

@Roman Pokrovskij 2017-08-27 12:26:44

Accessing struct in array should be quicker just because of no additional referencing required. Boxing/Unboxing is case for linq.

@Saeed Dini 2017-10-24 13:15:22

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.

@Jason Williams 2017-07-20 18:36:18

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

@N_E 2016-03-27 22:16:35

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.

@Ivan 2017-03-12 17:05:11

This is the best clue of all, IMHO.

@akazemis 2016-05-26 14:31:11

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)

@Vikram 2015-08-31 08:50:01

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

@ILoveFortran 2009-02-28 16:33:23

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.

@user166390 2011-01-27 18:36:57

+1 Yes, I agree on #1 entirely (this is a huge advantage when dealing with things like images, etc) and for pointing out that they are different from "normal objects" and there is know way of knowing this except by existing knowledge or examining the type itself. Also, you can't cast a null value to a struct type :-) This is actually one case where I almost wish there was some 'Hungarian' for non-Core value-types or a mandatory 'struct' keyword at variable declaration site.

@supercat 2012-07-24 21:33:50

@pst: It is true that one has to know something is a struct to know how it will behave, but if something is a struct with exposed fields, that's all one has to know. If an object exposes a property of an exposed-field-struct type, and if code reads that struct to a variable and modifies, one can safely predict that such action will not affect the object whose property was read unless or until the struct is written back. By contrast, if the property were a mutable class type, reading it and modifying it might update the underlying object as expected, but...

@supercat 2012-07-24 21:40:04

...it might also end up changing nothing, or it might change or corrupt objects that one didn't intend to change. Having code whose semantics say "change this variable all you like; changes won't do anything until you explicitly store them someplace" seems clearer than having code which says "You're getting a reference to some object, which might shared with any number of other references, or might not be shared at all; you'll have to figure out who else might have references to this object to know what will happen if you change it."

@Matt Stephenson 2015-09-11 19:00:02

Spot on with #1. A list full of structs can squeeze much more relevant data into L1/L2 caches than a list full of object references, (for the right size struct).

@weberc2 2015-11-20 18:11:49

Inheritance is rarely the right tool for the job, and reasoning too much about performance without profiling is a bad idea. Firstly, structs can be passed by reference. Secondly, passing by reference or by value is rarely a significant performance issue. Lastly, you're not accounting for the additional heap allocation and garbage collection that needs to take place for a class. Personally, I prefer to think of structs as plain-old-data and classes as things that do things (objects) although you can define methods on structs as well.

@Abdul 2016-12-22 19:49:08

@ILoveFortran "Passing structs as arguments is more expensive than classes." - In that case, how come primitives such as Int32 are implemented as structs instead of classes?

@Backwards_Dave 2017-11-21 00:13:38

@ILoveFortran couldn't you just as easily say that objects behave differently to "normal structs" and if the person doesn't know they are dealing with an object rather than a struct, they might assume the value is copied when passed as a param to a method.

@IAbstract 2011-08-07 13:44:41

The source referenced by the OP has some credibility ...but what about Microsoft - what is the stance on struct usage? I sought some extra learning from Microsoft, and here is what I found:

Consider defining a structure instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.

Do not define a structure unless the type has all of the following characteristics:

  1. It logically represents a single value, similar to primitive types (integer, double, and so on).
  2. It has an instance size smaller than 16 bytes.
  3. It is immutable.
  4. It will not have to be boxed frequently.

Microsoft consistently violates those rules

Okay, #2 and #3 anyway. Our beloved dictionary has 2 internal structs:

[StructLayout(LayoutKind.Sequential)]  // default for structs
private struct Entry  //<Tkey, TValue>
{
    //  View code at *Reference Source
}

[Serializable, StructLayout(LayoutKind.Sequential)]
public struct Enumerator : 
    IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, 
    IDictionaryEnumerator, IEnumerator
{
    //  View code at *Reference Source
}

*Reference Source

The 'JonnyCantCode.com' source got 3 out of 4 - quite forgivable since #4 probably wouldn't be an issue. If you find yourself boxing a struct, rethink your architecture.

Let's look at why Microsoft would use these structs:

  1. Each struct, Entry and Enumerator, represent single values.
  2. Speed
  3. Entry is never passed as a parameter outside of the Dictionary class. Further investigation shows that in order to satisfy implementation of IEnumerable, Dictionary uses the Enumerator struct which it copies every time an enumerator is requested ...makes sense.
  4. Internal to the Dictionary class. Enumerator is public because Dictionary is enumerable and must have equal accessibility to the IEnumerator interface implementation - e.g. IEnumerator getter.

Update - In addition, realize that when a struct implements an interface - as Enumerator does - and is cast to that implemented type, the struct becomes a reference type and is moved to the heap. Internal to the Dictionary class, Enumerator is still a value type. However, as soon as a method calls GetEnumerator(), a reference-type IEnumerator is returned.

What we don't see here is any attempt or proof of requirement to keep structs immutable or maintaining an instance size of only 16 bytes or less:

  1. Nothing in the structs above is declared readonly - not immutable
  2. Size of these struct could be well over 16 bytes
  3. Entry has an undetermined lifetime (from Add(), to Remove(), Clear(), or garbage collection);

And ... 4. Both structs store TKey and TValue, which we all know are quite capable of being reference types (added bonus info)

Hashed keys notwithstanding, dictionaries are fast in part because instancing a struct is quicker than a reference type. Here, I have a Dictionary<int, int> that stores 300,000 random integers with sequentially incremented keys.

Capacity: 312874
MemSize: 2660827 bytes
Completed Resize: 5ms
Total time to fill: 889ms

Capacity: number of elements available before the internal array must be resized.

MemSize: determined by serializing the dictionary into a MemoryStream and getting a byte length (accurate enough for our purposes).

Completed Resize: the time it takes to resize the internal array from 150862 elements to 312874 elements. When you figure that each element is sequentially copied via Array.CopyTo(), that ain't too shabby.

Total time to fill: admittedly skewed due to logging and an OnResize event I added to the source; however, still impressive to fill 300k integers while resizing 15 times during the operation. Just out of curiosity, what would the total time to fill be if I already knew the capacity? 13ms

So, now, what if Entry were a class? Would these times or metrics really differ that much?

Capacity: 312874
MemSize: 2660827 bytes
Completed Resize: 26ms
Total time to fill: 964ms

Obviously, the big difference is in resizing. Any difference if Dictionary is initialized with the Capacity? Not enough to be concerned with ... 12ms.

What happens is, because Entry is a struct, it does not require initialization like a reference type. This is both the beauty and the bane of the value type. In order to use Entry as a reference type, I had to insert the following code:

/*
 *  Added to satisfy initialization of entry elements --
 *  this is where the extra time is spent resizing the Entry array
 * **/
for (int i = 0 ; i < prime ; i++)
{
    destinationArray[i] = new Entry( );
}
/*  *********************************************** */  

The reason I had to initialize each array element of Entry as a reference type can be found at MSDN: Structure Design. In short:

Do not provide a default constructor for a structure.

If a structure defines a default constructor, when arrays of the structure are created, the common language runtime automatically executes the default constructor on each array element.

Some compilers, such as the C# compiler, do not allow structures to have default constructors.

It is actually quite simple and we will borrow from Asimov's Three Laws of Robotics:

  1. The struct must be safe to use
  2. The struct must perform its function efficiently, unless this would violate rule #1
  3. The struct must remain intact during its use unless its destruction is required to satisfy rule #1

...what do we take away from this: in short, be responsible with the use of value types. They are quick and efficient, but have the ability to cause many unexpected behaviors if not properly maintained (i.e. unintentional copies).

@supercat 2012-07-23 17:52:22

I don't think the runtime ever calls any struct constructor when creating an array of struct. The reason most languages forbid structs from having a default constructor is not because calling them would make array construction inefficient, but rather because it would be confusing to have struct constructors called in some cases but not others.

@supercat 2012-07-23 18:03:56

As for Microsoft's rules, the rule about immutability seems to be designed to discourage use of value types in a such a way that their behavior would differ from those of reference types, notwithstanding the fact that piecewise-mutable value semantics can be useful. If having a type be piecewise-mutable would make it easier to work with, and if storage locations of the type should be logically detached from each other, the type should be a "mutable" struct.

@Justin Morgan 2012-10-03 14:35:21

Bear in mind that readonly != immutable.

@supercat 2013-03-06 16:45:46

The fact that many of Microsoft's types violate those rules does not represent a problem with those types, but rather indicates that the rules should not apply to all structure types. If a structure represents a single entity [as with Decimal or DateTime], then if it would not abide by the other three rules, it should be replaced by a class. If a structure holds a fixed collection of variables, each of which may hold any value that would be valid for its type [e.g. Rectangle], then it should abide by different rules, some of which are contrary to those for "single-value" structs.

@IAbstract 2013-03-06 18:09:27

@supercat: you pretty well summed up my dissertation in a small paragraph :)

@supercat 2013-03-06 18:18:40

@IAbstract: Some people would justify the Dictionary entry type on the basis that it's an internal type only, performance was considered more important than semantics, or some other excuse. My point is that a type like Rectangle should have its contents exposed as individually-editable fields not "because" the performance benefits outweigh the resulting semantic imperfections, but because the type semantically represents a fixed set of independent values, and so the mutable struct is both more performant and semantically superior.

@supercat 2013-03-06 18:31:37

@IAbstract: If I had the power to change one early document from .net, it would probably be that one about structures. Were I writing the document, I would suggest that structures should to the extent possible fit one of two patterns--either the one described, or else a collection of independent public fields. In cases where the latter is what's needed, I think it's crazy to suggest that one should make structures pretend to be immutable class objects, which can do only awkwardly the things that exposed-field structures can do well.

@IAbstract 2013-03-06 18:43:12

@supercat: I agree ... and the whole point of my answer was that the 'guidelines' are pretty weak and structs should be used with full knowledge and understanding of the behaviors. See my answer on mutable struct here: stackoverflow.com/questions/8108920/…

@supercat 2013-03-06 18:51:32

@IAbstract: Yup. My point was that the "immutable structs are evil" people make an exception for internal-only performance-critical types like those to which you refer, but the real exception should be much broader. BTW, do you like my ".net is not Java" comment?

@Ion Todirel 2013-07-08 20:54:16

this is interesting if you make a contrast to C/C++, where the recommended way is to pass objects by value

@IAbstract 2013-07-08 21:14:00

@IonTodirel: if I were qualified to make the contrast I would. :) I don't know C/C++ well enough to go there. However, that is why the question is tagged for C#.

@supercat 2013-07-25 16:01:34

@IonTodirel: I thought the recommended C++ approach was to pass the values of object either by reference or by "const reference"; the C# approach when using class types is equivalent to passing pointers to objects, which is disparaged in C++ in cases where it isn't necessary.

@Ion Todirel 2013-07-26 03:15:24

@supercat, certainly, I was referring to special cases where you need to transport copies from a function/thread to another, because the original is subject to destruction or invalidation

@supercat 2013-07-26 15:56:44

@IonTodirel: That makes sense. The real key there is that in cases where an object defines a sensible means of copying, such means is a language feature rather than being an inconsistently-implemented interface.

@IAbstract 2015-06-11 18:46:35

Any explanation why there was a down-vote? Seriously? 340 up-votes and the one down-vote cannot be explained?

@Jo So 2016-02-16 01:36:25

@IAbstract: Get over it. Life has to go on :-)

@IAbstract 2016-02-16 16:42:40

@JoSo: believe me, I'm not concerned about it :) ... I laughed when I saw that.

@Panzercrisis 2016-04-21 15:12:11

I wonder if the increasing tendency towards 64-bit architecture weighs on the 16-byte advice by Microsoft? If I compile a struct in a dll with 32-bit, everything comes out as 4-byte members. If I compile it and tell Visual Studio to target "Any CPU", everything comes out as 8-byte members. I think Microsoft technically meant "no more than 16-bytes", as opposed to "less than 16-bytes", but does the general rule of thumb that people should follow (whether Microsoft's advice or not) say to just use structs with four or less members, whether they are references, values, or both?

@IAbstract 2016-04-21 16:43:06

@Panzercrisis: Microsoft technically meant "no more than 16-bytes" ...I agree this could be the case. When maintained as a Value type, then following the rule of thumb would infer 4 or fewer members. If the struct is cast to an interface (becoming a Reference type), then I would completely ignore the rule of thumb personally. This could very well be the reason that the Dictionary's enumerator has reference type members and is certainly larger than 16 bytes.

@BornToCode 2016-08-11 08:24:54

Could you please explain the quote you brought from msdn use struct if they are commonly embedded in other objects - why? what difference does it make, and especially if it's embedded in other objects it's going to live on the heap anyway (just like a class) so why use struct?

@Cryo Erger 2014-11-20 20:02:07

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.

@HimBromBeere 2015-09-10 14:45:41

Structures can NOT be inherited, see msdn.microsoft.com/en-us/library/0taef578.aspx

@mathk 2014-10-15 17:27:58

It seems to me that struct have no strong semantic that give the user a strong idea of when to use it.

It resemble as a class but lake most of its feature. It is a kind of degraded version of a class. There is a lot of says about when not use it but very few on when to use it.

IMO, there is no reason why struct should be implemented in a OO language at the first place. Actually primitive type should not exist in a pure OO language but I digress.

It might be a way to optimize stuff. A kind of boxing free things that can be optimize on some call site.

My 2 cent, I would say that it violated the KISS of the language principle and avoid it as much has I can.

@IAbstract 2014-10-17 15:40:01

Structs are value (by default, primitive) types: int, bool, etc. What does semantics have to do with "when to use a struct?". The existence of structs in a language has nothing to do with OO or semantics. This question is specific to C# (which has primitives and structs), not general OO philosophies. Your answer is opinionated and philosophical.

@mathk 2014-10-23 08:04:25

Semantics is the meaning of things. Now if you don't care about semantics then you must answer with a coin flip to the question. "when to use a struct?" ? "When you feel it is a good[bad] day". After-all you can do whatever you want. Beside you said that C# has primitive and struct, sure enough. But is not because a language implement a feature that it make sense to use it. I have seen C++ teams that could not work together just because because they could not understand the respective implementation. C++ have so many idiomatic way of resolving an issue that it make it many language in one.

@mathk 2014-10-23 08:05:04

So I am advising not to use struct in C# or to avoid it as much as you can. It might be an opinion but there is some argument behind it.

@IAbstract 2014-10-26 15:20:42

My question to you specifically was "what does semantics have to do with when to use a struct"? I was not saying that semantics has nothing to do with the decision. It is clear: if you want value semantics, use a struct. I understand that there is a lot of opinion about using structs and a blanket statement of "avoid as much as you can" it pretty lame and certainly has no value as an objective answer.

@J_hajian_nzd 2014-05-23 09:52:52

A class is a reference type. When an object of the class is created, the variable to which the object is assigned holds only a reference to that memory. When the object reference is assigned to a new variable, the new variable refers to the original object. Changes made through one variable are reflected in the other variable because they both refer to the same data. A struct is a value type. When a struct is created, the variable to which the struct is assigned holds the struct's actual data. When the struct is assigned to a new variable, it is copied. The new variable and the original variable therefore contain two separate copies of the same data. Changes made to one copy do not affect the other copy. In general, classes are used to model more complex behavior, or data that is intended to be modified after a class object is created. Structs are best suited for small data structures that contain primarily data that is not intended to be modified after the struct is created.

Classes and Structs (C# Programming Guide)

@supercat 2014-05-27 17:39:40

Structures are also very good in cases where it's necessary to fasten a few related-but-independent variables together with duct tape (e.g. the coordinates of a point). The MSDN guidelines are reasonable if one is trying to produce structures which behave like objects, but are far less appropriate when designing aggregates; some of them are almost precisely wrong in the latter situation. For example, the greater the degree of independence of the variables encapsulated by a type, the greater the advantage of using an exposed-field structure rather than an immutable class.

@Usman Zafar 2014-01-22 10:17:43

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
}

@supercat 2014-01-22 17:04:33

Immutable reference types like string are semantically equivalent to values, and storing a reference to an immutable object into a field does not entail a heap allocation. The difference between a struct with exposed public fields and a class object with exposed public fields is that given the code sequence var q=p; p.X=4; q.X=5;, p.X will have the value 4 if a is a structure type, and 5 if it's a class type. If one wishes to be able to conveniently modify the members of the type, one should select 'class' or 'struct' based upon whether one wants changes to q to affect p.

@Usman Zafar 2014-01-23 05:33:13

Yes i agree the reference variable will be on the stack but the object it refers will exist on the heap. Although structs and classes behave differently when assigned to a different variable, but i don't think thats a strong deciding factor.

@supercat 2014-01-23 13:34:07

Mutable structs and mutable classes behave completely differently; if one is right, the other will most likely be wrong. I'm not sure how behavior wouldn't be a deciding factor in determining whether to use a struct or a class.

@Usman Zafar 2014-01-24 02:01:43

I said it’s not a strong deciding factor because often when when you are creating a class or struct you are not sure how it will be used. So you concentrate on how things make more sense from design perspective. Anyways i have never seen at a single place in .NET library where a struct contains a reference variable.

@supercat 2014-01-25 17:32:40

Structure type ArraySegment<T> encapsulates a T[], which is always a class type. Structure type KeyValuePair<TKey,TValue> is often used with class types as the generic parameters.

@IAbstract 2014-10-17 20:34:03

BitVector32 is broken per your example as it uses a 32-byte array which is a reference type. This is not a hard and fast way to determine whether you need a struct.

@GameDeveloper 2015-08-07 13:28:37

This is the best answer. If you need a Value semantics, use a struct (passing by argument generate a copy instead of allowing editing the original). It is possible for big collections of data a struct actually improve performance but that should be verified by profiling and shipped with unit tests showing you not altered the functionality of the program. If you want to include part of this comment in the answer as edit feel free to do that ^^

@rockXrock 2013-08-30 08:22:20

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.

@supercat 2013-08-30 17:10:37

A substantial usage case which Microsoft ignores is when one wants a variable of type Foo to encapsulate a fixed collection of independent values (e.g. coordinates of a point) which one will sometimes want to pass around as a group and sometimes want to change independently. I've not found any pattern for using classes which combines both purposes nearly as nicely as a simple exposed-field struct (which, being a fixed collection of independent variables, fits the bill perfectly).

@stakx 2013-08-31 09:22:00

@supercat: I think it's not entirely fair to blame Microsoft for that. The real issue here is that C# as an object-oriented language simply does not focus on plain record types that only expose data without much behavior. C# is not a multi-paradigm language to the same extent that e.g. C++ is. That being said, I also believe very few people program pure OOP, so perhaps C# is too idealistic a language. (I for one have recently begun exposing public readonly fields in my types, too, because creating read-only properties are simply too much work for practically no benefit.)

@supercat 2013-08-31 22:44:03

@stakx: There's no need for it to "focus" on such types; recognizing them for what they are would suffice. The biggest weakness with C# with regard to structs is its biggest problem in many other areas too: the language provides inadequate facilities for indicating when certain transformations are or are not appropriate, and the lack of such facilities drives unfortunate design decisions. For example, 99% of "mutable structs are evil" stems from the compiler's turning MyListOfPoint[3].Offset(2,3); into var temp=MyListOfPoint[3]; temp.Offset(2,3);, a transform which is bogus when applied...

@supercat 2013-08-31 22:50:03

...to the Offset method. The proper way to prevent such bogus code shouldn't be make structs needlessly immutable, but instead to allow methods like Offset to be tagged with an attribute forbidding the aforementioned transform. Implicit numerical conversions too could have been much better if they could be tagged so as to be applicable only in cases where their invocation would be obvious. If overloads exist for foo(float,float) and foo(double,double), I would posit that trying to use a float and a double often shouldn't apply an implicit conversion, but should instead be an error.

@supercat 2013-08-31 23:00:25

A direct assignment of a double value to a float, or passing it to a method which can take a float argument but not double, would almost always do what the programmer intended. By contrast, assigning float expression to double without an explicit typecast is often a mistake. The only time allowing implicit double->float conversion would cause problems would be when it would cause a less-than-ideal overload to be selected. I'd posit that the right way to prevent that shouldn't have been forbidding implcit double->float, but tagging overloads with attributes to disallow conversion.

@JoshBerke 2009-02-06 17:40:26

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.

@TheSmurf 2009-02-06 17:42:09

Everyone knows that. Seems like he's looking for more than a "struct is a value type" answer.

@BobbyShaftoe 2009-02-06 17:46:48

Not everyone knows that. That is clearly one case.

@JoshBerke 2009-02-06 17:55:16

It the most basic case and should be stated for anyone who reads this post and doesn't know that.

@TheSmurf 2009-02-06 18:02:32

Not that this answer isn't true; it obviously is. That's not really the point.

@TheSmurf 2009-02-06 18:03:10

@Josh: For anyone who doesn't know it already, simply saying it is an insufficient answer, since it's quite likely they don't know what it means, either.

@Daniel Earwicker 2009-02-06 18:50:19

I've just downvoted this because I think one of the other answers should be at the top - any answer that says "For interop with unmanaged code, otherwise avoid".

@Eva 2013-03-09 21:02:10

sigh Answers like these are the reason why I have to post a tutorial on basic elements of a language in my questions because people would rather give the answer to simple things than actually read the question.

@nawfal 2013-08-28 10:13:06

I canceled my downvote. I think Josh has a point considering OP has not mentioned it in his question. Everything else is speculation.

@Subby 2014-07-22 12:28:20

Look at the OP's question. It's begging that someone knowledge sheds light on the problem. I.e. what is/when to use a Struct etc. This answer, while being perfectly true, needs a little more meat! And at 34.1k reputation points, I'd expect a little more. The downvoters shouldn't downvote without giving a reason. But your edit should include more information as a result of those downvotes.

@JoshBerke 2014-07-24 15:55:56

@Subby probally, keep in mind I didn't have 34k rep five years ago:-)

@Subby 2014-07-25 08:02:21

@JoshBerke true dat! :)

@MrDosu 2014-10-23 11:59:49

+1 for focusing on semantics. Of more people would program more based on paradigms and semantics we would not have all these language/platform/api/format wars.

@Mike de Klerk 2015-09-03 08:29:08

A class can be checked against null, so you know whether it has been initalized properly. With a struct you are never sure (see default(struct)). See: msdn.microsoft.com/nl-nl/library/xwth0h0d.aspx

@Tom Lint 2018-02-15 10:04:19

@MikedeKlerk Not sure why that would matter. If uninitialized structs are causing issues in C#, then you've got bigger problems.

@Rabbit 2013-07-03 14:20:39

Struct can be used to improve garbage collection performance. While you usually don't have to worry about GC performance, there are scenarios where it can be a killer. Like large caches in low latency applications. See this post for an example:

http://00sharp.wordpress.com/2013/07/03/a-case-for-the-struct/

@bUKaneer 2012-09-17 15:42:08

From the C# Language specification:

1.7 Structs

Like classes, structs are data structures that can contain data members and function members, but unlike classes, structs are value types and do not require heap allocation. A variable of a struct type directly stores the data of the struct, whereas a variable of a class type stores a reference to a dynamically allocated object. Struct types do not support user-specified inheritance, and all struct types implicitly inherit from type object.

Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. The use of structs rather than classes for small data structures can make a large difference in the number of memory allocations an application performs. For example, the following program creates and initializes an array of 100 points. With Point implemented as a class, 101 separate objects are instantiated—one for the array and one each for the 100 elements.

class Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

class Test
{
   static void Main() {
      Point[] points = new Point[100];
      for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
   }
}

An alternative is to make Point a struct.

struct Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}

Now, only one object is instantiated—the one for the array—and the Point instances are stored in-line in the array.

Struct constructors are invoked with the new operator, but that does not imply that memory is being allocated. Instead of dynamically allocating an object and returning a reference to it, a struct constructor simply returns the struct value itself (typically in a temporary location on the stack), and this value is then copied as necessary.

With classes, it is possible for two variables to reference the same object and thus possible for operations on one variable to affect the object referenced by the other variable. With structs, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other. For example, the output produced by the following code fragment depends on whether Point is a class or a struct.

Point a = new Point(10, 10);
Point b = a;
a.x = 20;
Console.WriteLine(b.x);

If Point is a class, the output is 20 because a and b reference the same object. If Point is a struct, the output is 10 because the assignment of a to b creates a copy of the value, and this copy is unaffected by the subsequent assignment to a.x.

The previous example highlights two of the limitations of structs. First, copying an entire struct is typically less efficient than copying an object reference, so assignment and value parameter passing can be more expensive with structs than with reference types. Second, except for ref and out parameters, it is not possible to create references to structs, which rules out their usage in a number of situations.

@supercat 2012-09-17 23:16:23

While the fact that references to structs cannot be persisted is sometimes a limitation, it is also a very useful characteristic. One of the major weaknesses of .net is that there is no decent way to pass outside code a reference to a mutable object without forever losing control of that object. By contrast, one may safely give an outside method a ref to a mutable struct and know that any mutations that outside method will perform on it will be done before it returns. It's too bad .net doesn't have any concept of ephemeral parameters and function return values, since...

@supercat 2012-09-17 23:20:18

...that would allow the advantageous semantics of structs passed by ref to be achieved with class objects. Essentially, local variables, parameters, and function return values could be persistable (default), returnable, or ephemeral. Code would be forbidden from copying ephemeral things to anything that would outlive the present scope. Returnable things would be like ephemeral things except that they could be returned from a function. The return value of a function would be bound by the tightest restrictions applicable to any of its "returnable" parameters.

@supercat 2012-07-24 22:07:44

Structure types in C# or other .net languages are generally used to hold things that should behave like fixed-sized groups of values. A useful aspect of structure types is that the fields of a structure-type instance can be modified by modifying the storage location in which it is held, and in no other way. It's possible to code a structure in such a way that the only way to mutate any field is to construct a whole new instance and then use a struct assignment to mutate all the fields of the target by overwriting them with values from the new instance, but unless a struct provides no means of creating an instance where its fields have non-default values, all of its fields will be mutable if and if the struct itself is stored in a mutable location.

Note that it's possible to design a structure type so that it will essentially behave like a class type, if the structure contains a private class-type field, and redirects its own members to that of the wrapped class object. For example, a PersonCollection might offer properties SortedByName and SortedById, both of which hold an "immutable" reference to a PersonCollection (set in their constructor) and implement GetEnumerator by calling either creator.GetNameSortedEnumerator or creator.GetIdSortedEnumerator. Such structs would behave much like a reference to a PersonCollection, except that their GetEnumerator methods would be bound to different methods in the PersonCollection. One could also have a structure wrap a portion of an array (e.g. one could define an ArrayRange<T> structure which would hold a T[] called Arr, an int Offset, and an int Length, with an indexed property which, for an index idx in the range 0 to Length-1, would access Arr[idx+Offset]). Unfortunately, if foo is a read-only instance of such a structure, current compiler versions won't allow operations like foo[3]+=4; because they have no way to determine whether such operations would attempt to write to fields of foo.

It's also possible to design a structure to behave a like a value type which holds a variable-sized collection (which will appear to be copied whenever the struct is) but the only way to make that work is to ensure that no object to which the struct holds a reference will ever be exposed to anything which might mutate it. For example, one could have an array-like struct which holds a private array, and whose indexed "put" method creates a new array whose content is like that of the original except for one changed element. Unfortunately, it can be somewhat difficult to make such structs perform efficiently. While there are times that struct semantics can be convenient (e.g. being able to pass an array-like collection to a routine, with the caller and callee both knowing that outside code won't modify the collection, may be better than requiring both caller and callee to defensively copy any data they're given), the requirement that class references point to objects that will never be mutated is often a pretty severe constraint.

@Sujit 2012-09-17 11:21:43

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

@supercat 2012-09-17 15:04:12

Copying small structures or passing by value is as cheap as copying or passing a class reference, or passing the structures by ref. Passing any size structure by ref costs the same as passing a class reference by value. Copying any size structure or passing by value is cheaper than performing a defensive copy of a class object and storing or passing a reference to that. The big times classes are better than structs for storing values are (1) when the classes are immutable (so as to avoid defensive copying), and each instance which is created will be passed around a lot, or...

@supercat 2012-09-17 15:10:38

...(2) when for various reasons a struct would simply not be usable [e.g. because one needs to use nested references for something like a tree, or because one needs polymorphism]. Note that when using value types, one should generally expose fields directly absent a particular reason not to (whereas with most class types fields should be wrapped within properties). Many of the so-called "evils" of mutable value types stem from needless wrapping of fields in properties (e.g. while some compilers would allow one to call a property setter on a read-only struct because it would sometimes...

@supercat 2012-09-17 15:15:08

...do the right thing, all compilers would properly reject attempts to directly set fields on such structures; the best way to ensure compilers reject readOnlyStruct.someMember = 5; is not to make someMember a read-only property, but instead make it a field.

@ 2009-02-06 19:21:34

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.

@Marc Gravell 2011-10-22 12:14:22

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.

@Jordão 2012-10-15 16:22:43

+1 Interesting answer. Would you be willing to share any real world anecdotes about such an approach being used?

@Marc Gravell 2012-10-15 17:18:54

@Jordao in on mobile, but search google for: +gravell +"assault by GC"

@Jordão 2012-10-15 19:15:35

Thanks a lot. I found it here.

@supercat 2013-09-24 16:52:35

I wonder what performance would be like if one defined an ICustomer, and had a CustomerRef struct which implemented that interface, held a single int index, and acted in appropriate fashion upon the items of the array? I would think that if one made the methods which take a Customer instead accept an ICustomer generically it should be possible to get performance comparable to the current approach without having to widely expose the underlying array.

@supercat 2013-09-24 16:55:21

Such a thing is probably a YAGNI, but if e.g. the customer array would be in danger of hitting the 2GB limit, one could change the array-access code from customers[index] to customers[index >> 16][index & 65535] without having to affect anything outside CustomerRef.

@Marc Gravell 2013-09-24 16:56:29

@supercat or just enable the large array support in 4.5

@supercat 2013-09-24 17:28:02

@MarcGravell: Never used that. In any case, my point was that there are various means via which the ICustomer approach would allow one to migrate away from using a monolithic array should the need arise (the 2GB limit was one reason why it might do so, but not the only one). Incidentally, one thing your blog doesn't mention as a "cost" of your approach is that the GC has no way of knowing which array slots have references to them. That reduces the cost of GC, but means it may be necessary for an application to track such things itself.

@Eris 2014-02-11 15:39:13

@MarcGravell Why did you mention : use an array (not list) ? List I believe , uses an Array behind scenes. no ?

@user1323245 2014-09-30 12:00:59

@RoyiNamir I was curious about this as well, but I believe the answer lies in the second paragraph of Marc's answer. "However, accessing it directly in an array does not copy the struct - it is in-place (contrast to a list indexer, which does copy)."

@SnapJag 2009-02-06 19:17:59

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.

@supercat 2013-07-25 16:04:53

Structures may be sensibly used to represent lightweight immutable objects, or they may be sensibly used to represent fixed sets of related-but-independent variables (e.g. the coordinates of a point). The advice on that page is good for structs which are designed to serve the former purpose, but is wrong for structs which are designed to serve the latter purpose. My present thinking is that structs which have any private fields should generally meet the indicated description, but many structs should expose their entire state via public fields.

@supercat 2013-07-25 16:15:01

If the specification for a "3d point" type indicates that its entire state is exposed via readable members x, y, and z, and it's possible to create an instance with any combination of double values for those coordinates, such a spec would compel it to behave semantically identically to an exposed-field struct except for some details of multi-threaded behavior (the immutable class would be better in some cases, while the exposed-field struct would be better in others; a so-called "immutable" struct would be worse in every case).

@Maurice Flanagan 2009-02-06 18:09:02

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.

@Stephen Martin 2009-02-06 18:32:07

The StructLayoutAttribute can be applied to structs or classes so this is not a reason to use structs.

@Backwards_Dave 2017-11-21 00:41:09

Why does it make sense if you are just passing an argument to an unmanaged method call?

@mjfgates 2009-02-06 18:25:49

I use structs for packing or unpacking any sort of binary communication format. That includes reading or writing to disk, DirectX vertex lists, network protocols, or dealing with encrypted/compressed data.

The three guidelines you list haven't been useful for me in this context. When I need to write out four hundred bytes of stuff in a Particular Order, I'm gonna define a four-hundred-byte struct, and I'm gonna fill it with whatever unrelated values it's supposed to have, and I'm going to set it up whatever way makes the most sense at the time. (Okay, four hundred bytes would be pretty strange-- but back when I was writing Excel files for a living, I was dealing with structs of up to about forty bytes all over, because that's how big some of the BIFF records ARE.)

@Backwards_Dave 2017-11-21 00:39:47

Couldn't you just as easily use a reference type for that though?

@leppie 2009-02-06 18:15:06

With the exception of the valuetypes that are used directly by the runtime and various others for PInvoke purposes, you should only use valuetypes in 2 scenarios.

  1. When you need copy semantics.
  2. When you need automatic initialization, normally in arrays of these types.

@IAbstract 2011-08-07 11:38:50

#2 seems to be part of the reason for struct prevalence in .Net collection classes..

@supercat 2013-08-28 20:02:09

If the first thing one would do upon creating a storage location of a class type would be to create a new instance of that type, store a reference to it in that location, and never copy the reference anywhere else nor overwrite it, then a struct and class would behave identically. Structs have a convenient standard way to copy all of the fields from one instance to another, and will generally offer better performance in cases where one would never duplicate a reference to a class (except for the ephemeral this parameter used to invoke its methods); classes allow one to duplicate references.

@BC. 2009-02-06 18:12:58

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.

@Franci Penov 2009-02-06 17:58:07

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.

@Alex 2013-07-10 11:55:56

Yes, but large structs can be more expensive than class references (when passing around to methods).

@dsimcha 2009-02-06 17:40:45

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.

@user166390 2011-01-27 18:34:49

That is only one "caveat". Should also consider "lifting" of value-types and cases such as (Guid)null (it's okay to cast a null to a reference-type), among other things.

@Ion Todirel 2013-07-08 20:53:36

more expensive than in C/C++? in C++ the recommended way is to pass objects by value

@Luaan 2015-11-23 13:25:29

@IonTodirel Wasn't that for memory safety reasons, rather than performance? It's always a trade-off, but passing 32 B by stack is always(TM) going to be slower than passing a 4 B reference by register. However, also note that the use of "value / reference" is a bit different in C# and C++ - when you pass a reference to an object, you're still passing by value, even though you're passing a reference (you're passing the value of the reference, not a reference to the reference, basically). It's not value semantics, but it's technically "pass-by-value".

@Onur 2016-02-19 16:11:41

@Luaan Copying is only one aspect of costs. The extra indirection due to pointer/reference also costs per access. In some cases the struct can even be moved and thus doesn't even need to be copied.

@Winger Sendon 2017-07-27 18:15:26

@Onur that's interesting. How do you "move" without copying? I thought the asm "mov" instruction doesn't actually "move". It copies.

@Onur 2017-07-28 09:14:31

@WingerSendon To be honest, I'm not sure what I meant with moving without copying. Maybe I mixed this up with C++. But I wouldn't bother too much with the cost of copying if the struct is small enough. Copying a struct should be cheap since it's just a single contiguous area in memory.

@Brian 2009-02-06 17:44:34

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.

@Franci Penov 2009-02-06 17:54:57

I would disagree with that answer. Structs have a legitimate use in many scenarios. Here's an example - marshaling data cross processes in atomic manner.

@Brian 2009-02-06 18:01:13

Good point, interop/marshalling is another good reason.

@Erik Forbes 2009-02-06 20:43:09

You should edit your post and elaborate on your points - you've given your opinion, but you should back it up with why you take this opinion.

@Greg 2010-05-13 19:00:21

I think they need an equivalent of the Totin' Chip card (en.wikipedia.org/wiki/Totin%27_Chip) for using structs. Seriously.

@Subby 2014-07-22 12:30:10

@ErikForbes I agree with you 100%. It's sad to see answers like this coming from people who have those many points.

@Rohit Vipin Mathews 2015-06-02 10:34:22

How does a 87.5K person post an answer like this? Did he do it while he was a child?

@Andrew Arnold 2015-06-02 14:36:24

@Rohit - it was six years ago; site standards were very different then. this is still a bad answer, though, you're right.

@rory.ap 2015-09-18 17:47:03

@Rohit -- And how did it get so many up-votes? At present count, 22 people thought "this answer is useful".

@Rohit Vipin Mathews 2015-09-19 06:34:39

@roryap - 22? I see only 6 up votes.

@rory.ap 2015-09-19 11:57:43

@Rohit -- 22 up votes, 16 down votes. 22 - 16 = 6 total.

Related Questions

Sponsored Content

25 Answered Questions

[SOLVED] When should you use a class vs a struct in C++?

  • 2008-09-10 16:29:54
  • Alan Hinchcliffe
  • 327446 View
  • 754 Score
  • 25 Answer
  • Tags:   c++ oop class struct ooad

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

11 Answered Questions

[SOLVED] Why isn't sizeof for a struct equal to the sum of sizeof of each member?

18 Answered Questions

[SOLVED] What's the difference between struct and class in .NET?

8 Answered Questions

[SOLVED] Difference between 'struct' and 'typedef struct' in C++?

  • 2009-03-04 20:41:12
  • criddell
  • 434255 View
  • 703 Score
  • 8 Answer
  • Tags:   c++ struct typedef

12 Answered Questions

[SOLVED] typedef struct vs struct definitions

  • 2009-11-04 17:21:57
  • user69514
  • 540016 View
  • 660 Score
  • 12 Answer
  • Tags:   c struct typedef

16 Answered Questions

[SOLVED] Why are mutable structs “evil”?

4 Answered Questions

11 Answered Questions

4 Answered Questions

[SOLVED] C# class vs struct

  • 2012-12-22 22:16:45
  • Georgii Oleinikov
  • 2594 View
  • 2 Score
  • 4 Answer
  • Tags:   c# class struct

Sponsored Content