There are specific situations where narrowing the underlying type brings some advantages, for example performance related or forcing a particular memory layout when interfacing to unmanaged code.
Consider this sample:
using System;
public enum Operations_PerHourType // : byte
{
Holes = 1,
Pieces = 2,
Sheets = 3,
Strips = 4,
Studs = 5
}
class Program
{
static void Main()
{
long before = GC.GetTotalMemory(false);
var enums = new Operations_PerHourType[10000];
long after = GC.GetTotalMemory(false);
Console.WriteLine(after - before);
// output (byte): 12218 (I'm using Mono 2.8)
// output (Int32): 40960
}
}
This code consumes roughly 40 KB of the heap. Now specify (uncomment) the underlying type as byte
and recompile. Wow. Suddenly we only need roughly 10 KB.
Compacting memory like this may sometimes make a program slower, not faster, depending on particular access patterns and data sizes. There is no way to know for sure than to make some measurements and attempt to generalize to other possible circumstances. Sequential traversal of smaller data is usually faster.
However, developing a habit of specifying narrow types just because it is usually possible and sometimes crucial, is not a good idea. Memory savings rarely materialize due to memory alignment of surrounding wider data types. Performance is then either the same or slightly worse due to additional instructions needed to mask away padding bytes.
As another answer has already put it well, follow the Int32
crowd that the runtime is optimized for, until you have to start profiling and addressing real memory hogs in your application.