The msdn recommendations (listed in another answer) offer some recommendations. For performance, you should consider their use and the distinction between structures and classes. The most important thing is to use only structures when the type is the actual type of value, i.e. It has semantics of meanings. Using a class for a value type or structure for something that needs to be a reference type will quickly lead to confusing results with manual copies or unintended references. Also remember that structures should always be immutable.
Only in extremely performance-sensitive situations should you ignore any of these basic rules (example: a structure violates the rules for a List.Enumerator structure!).
Perf considerations for structs vs classes:
If you pass your structure as an argument to a method, you will create a copy of the structure each time. This is why documents recommend that you do not create structures larger than 16 bytes.
double Distance(Vector3D a, Vector3D b)
In the above scenario, a 3-doubling three-dimensional vector would be 24 bytes and would be larger than the recommended 16, but I would still argue that the structure makes sense, since this is clearly a value type, especially you have Vector2D containing two doubles (16 bytes) which are structure!
The key to making good use of structures and making them more efficient is to use them to localize the cache and avoid many distributions. To reuse the Vector example above if you have this method
double AverageDistanceFromOrigin(Vector3D[] points) // Single reference passed { double sum = 0.0; for(...) sum += Math.Sqrt(points[i].X... + ... + ...) // No copies return sum/points.Length; }
You can see a good performance difference in the structures. The reason is that now you pass one method (array) to the method, so there is no additional overhead for copying the structure for each call (note that the method does not call the distance method for each record in the array),
Array structures are also laid out sequentially in memory, for example [x1, y1, z1, x2, y2, ...], so the CPU will load, for example. 16 coordinates in the cache, which leads to several misses in the cache. Compare this with the implementation of class Vector3D : an array of vectors will now be allocated, and each entry in the array will also be a link, which should be allocated in a heap and then garbage collected. The array is now an array of links [ref to v1, ref to v2, ref to v3], each of which can have any address on the heap and cannot sit next to eachother. This can lead to even more cache flaws than to the case of structure.
- Use structs only if your type has semantics of values (and vice versa).
- Do not pass large structures individually to methods; Work on lists / arrays of structures to avoid copying.
- Don't consider the 16 byte limit a hard limit: you can use much larger structures, but remember to avoid passing them individually to methods.