I like using structs a lot.
So after reading this article, are there any other concerns I should have against using them all the time?
I like using structs a lot.
So after reading this article, are there any other concerns I should have against using them all the time?
You should make the following considerations about structs:
Equals and GetHashCode methods should be overriden for better performanceIEquatable<T> interface is recommended== and the != operators is also recommendedstruct Point { public int X, public int Y }. When it's used in a collection (e.g. List<Point>) iterating and modifying it would not update the value in the collection: foreach(var p in points /* points is Point[] */) { p.X = 3 }, because getting an element from the collection just gives you a copy (or a clone) of the element. The same is valid for passing struct values as method arguments.I almost never define custom structs. There just aren't that many natural value types around, IMO.
In particular, I would think very, very carefully before defining a mutable struct, especially if it mutates via an interface implementation. Mutable structs behave in ways which people don't expect at all, leading to code which is hard to understand.
I think it's worth reading "Choosing Between Classes and Structures" from "Design Guidelines For Developing Class Libraries".
In particular:
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.
Do you really develop types with all of those characteristics frequently?
Ask yourself the following questions about the set of data you're modeling with a struct:
I think if you can heartily answer "no" to all these questions, then there's no good reason not to use a struct. I think people use static subclasses in certain situations where a struct would be more than good enough.
A class is a lot simpler to implement correctly than a struct. If you implement a struct incorrectly it can give you some unexpected errors.
A struct should not be larger than 16 bytes, or you lose most of the performance benefits.
A struct is intended to be a value type, representing a single entity of some kind.
A struct should be immutable. That means that you never change one of the properties in a struct. If you want a struct value that is different you create a new value.
int called Moe, Larry, and Curly, public struct Stooge { public int Moe, Larry, Curly; }. Maybe for convenience add a constructor: public Stooge(int newMoe, int newLarry, int newCurly) {Moe = newMoe; Larry = newLarry; Curly = newCurly;}. Trying to put too much logic into a struct can be problematic, but there's a simple solution: don't. Someone who tries to pound nails with a screwdriver will find it to be an inferior hammer, but that doesn't mean a screwdriver isn't a good tool.Stooge should have no identity outside of the values they contain, such that an array of 100 Stooge instances would hold precisely the same information as 300 integers, then Stooge must be either a struct or an immutable class; while there are some cases where an exposed-field struct would be usable but an immutable class would be better, I would regard those as the exception rather than the rule. Given Stooges[] Stooge, if Stooge was a class, how would one change Stooges[3].Moe without affecting AnyOtherStooge.Moe? How much code would one have to examine...Stooge is defined as above, Stooges[3].Moe = 27; would do the job quite simply; knowing that Stooges[] is a Stooge, and Moe is a field of Stooge would be sufficient to define the behavior. If Stooge is an immutable class, one might be able to do Stooges[3] = Stooges[3].WithMoe(27);, but one would have to examine the WithMoe mehtod to confirm what it does, and examine the entire Stooge class to ensure it really is immutable, and that WithMoe copies all of its fields correctly. That's somehow an improvement?Use of structs should be limited to when all you really need is a small data structure. (as you read). I would only really use them for the smallest of datastructures like coordinates, offsets, and sometimes for graphics.
In many ways, you can think of structs in C# as being like scaled - down classes. They are basically the same as classes but designed more for cases where you simply want to group some data together. They differ from classes in the following ways: Some things to keep in mind