Reputation: 158171
When creating a simple data container class, what should it be?
Examples of the above:
struct MutableStruct
{
public string Text { get; set; }
public int Number { get; set; }
}
struct ImmutableStruct
{
public string Text { get; private set; }
public int Number { get; private set; }
public ImmutableStruct(string text, int number)
: this()
{
Text = text;
Number = number;
}
}
struct MutableStructWithConstructor
{
public string Text { get; set; }
public int Number { get; set; }
public MutableStructWithConstructor(string text, int number)
: this()
{
Text = text;
Number = number;
}
}
class MutableClass
{
public string Text { get; set; }
public int Number { get; set; }
}
class ImmutableClass
{
public string Text { get; private set; }
public int Number { get; private set; }
public ImmutableClass(string text, int number)
{
Text = text;
Number = number;
}
}
class MutableClassWithConstructor
{
public string Text { get; set; }
public int Number { get; set; }
public MutableClassWithConstructor(string text, int number)
{
Text = text;
Number = number;
}
}
Any good reasons we should choose one above another? Or are there mostly subjective preferences that separate them? Or does it depend a lot on the spesific use cases? If so in what use cases should you choose what and why?
Upvotes: 14
Views: 5528
Reputation: 50094
It really seems like almost all of the time structs are an unnecessary distraction from the ease and efficiency of classes.
Upvotes: 0
Reputation: 3159
Consider using classes whenever you need to provide object "functionality" as opposed to merely identity or state i.e. "values".
As has already been stated, structs are value types and as such will be copied wherever you use them. Also, there is a negligible performance difference when instantiating classes versus structs.
Upvotes: 0
Reputation: 1579
A couple of points on classes vs structs:
Classes are pass-by-reference which means that the same instance object is passed between functions. If you create MyClass in method A and call method B, method B changes the class and returns nothing to method A, method A sees the changes made in MyClass because they are refering to the same object. A reference is usually an int32, so no matter how big your class is it will be quick to call method B because it's only passing 4 bytes. Classes rely on the Garbage Collector to decide when it is no longer being used (smaller overhead in passing the class around but adds overhead to the garbage collector).
Structs are pass-by-value (or a value type). This means that the whole struct is copied when it is passed around. If your struct is big, this will take a long time. A change to the struct in Method B won’t show in method A unless it is returned (again costing time as it is pass by value), and Method A reads the return value. Structs are created on the stack and do not have a garbage collection overhead (you can see this if you examine your IL code).
There are many limitations in structs compared to classes, such as the lack of virtual methods and other polymorphic functionality.
It's best to favour classes, unless you are going to rapidly create and discard lots of objects in the same method (which drain system resources due to garbage collection), in which case favour structs.
Upvotes: 1
Reputation: 4820
Also, there's the rule of thumb that structs shouldn't be larger than 16 bytes - the size of a processor cache line.
Upvotes: 0
Reputation: 269498
Only use structs when you need value-type semantics, and try to avoid mutable structs completely.
Other than that, I think it comes down to personal, or team, preference and your particular requirements.
(These days I'm trying to use immutable objects whenever possible, which almost always necessitates passing values into the constructor.)
Upvotes: 2
Reputation: 29490
You should almost always prefer classes over structs. Use structs only when the object represents an (immutable) value.
If you need to change the object and it is safe to do so then make it mutable, else make it immutable and use cloning.
If the object is in a valid state when created with the default constructor, fine. Otherwise always provide your own constructor.
Upvotes: 3
Reputation: 16435
I usually do immutable classes with all the values being set/passed in via the constructor.
Upvotes: 0
Reputation: 1063328
Almost always a class; structs should really only be used for things that are values - for example, a complex-number, or a currency type/value pair - and should almost-without-exclusion be immutable.
A parameterless constructor is handy on mutable data if you are going to do data-binding, as this allows the system to create instances without additional code from yourself. A non-empty constructor is pretty-much essential for immutable data. For mutable data, an object initializer goes a long way towards that (although isn't quite the same in terms of validation etc):
var obj = new Person {Name="Fred", DateOfBirth=DateTime.Today};
Whether your types are immutable is up to you; mutable makes it easier to do data-binding and serialization. In general, you tend to see more mutable types in .NET, but this may change as we get into the parallel / many-core era.
Upvotes: 11