One thing that really gets under my skin is the overuse of structs. I hear arguments such as "structs are simple", "I don't have to instantiate it", or my personal favorite, "this is just a record." A struct can be complex, not instantiating something is not a good excuse, and structs are not "records" (usually this comes from Delphi programmers).
A struct should represent a single value. If it doesn't represent a single value, it shouldn't be a struct. That's the general guideline I follow when deciding whether or not to use a struct. In most cases, you should define a class.
Here is the criteria for making a struct:
-
Does it represent a single value?
-
Will the instance size be under 16 bytes?
-
Should it be immutable (modifications actually make a new copy in memory, forcing you to pass by ref to methods)?
-
Will this rarely need to be boxed (cast to an object)?
-
Will it usually be short-lived?
-
Will it mostly be embedded in other objects?
If you can answer yes to all those questions, then you may indeed have a struct on your hands.
This should be a struct:
public struct Coordinate
{
private decimal latitude;
private decimal longitude;
public Coordinate(decimal latitude, decimal longitude)
{
this.latitude = latitude;
this.longitude = longitude;
}
public decimal Latitude
{
get
{
return latitude;
}
set
{
this.latitude = value;
}
}
public decimal Longitude
{
get
{
return longitude;
}
set
{
this.longitude = value;
}
}
}
A coordinate is a well-defined value, it's small, and there's no problem making it immutable.
This should not be a struct:
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public Address(string street, string city, string state, string country, string zipCode)
{
Street = street;
City = city;
State = state;
Country = country;
ZipCode = zipCode;
}
}
Although one could argue that an address is a well-defined value (I'd argue that it has too many composite parts), it is clearly going to be larger than 16-bytes. In fact, if you have even one string field, it most likely should be a class anyway.
Note that these are simple examples. Over the course of my career I've seen huge classes that are inexplicably defined as structs. Rarely have I seen a class that should have been defined as a struct.