Generally, you should always use the most specific data type for your data possible.
If, for example, you are using Entity Framework to pull data from a database, EF will automatically use the data type closest to the one used in the database.
There are two problems with this in C#.
First, most C# developers use only int
, to represent whole numbers (unless there is a reason to use long
). This means that other developers will not think to check the data type, so they will get the overflow errors mentioned above.
The second, and more critical issue, is/was that .NET's original arithmetic operators only supported int
, uint
, long
, ulong
, float
, double, and decimal
*. This is still the case today (see section 7.8.4 in C# 5.0 language spec). You can test this yourself using the following code:
byte a, b;
a = 1;
b = 2;
var c = a - b; //In visual studio, hover over "var" and the tip will indicate the data type, or you can get the value from cName below.
string cName = c.GetType().Namespace + '.' + c.GetType().Name;
The result of our byte
-byte
is an int
(System.Int32
).
These two issues gave rise to the "only use int for whole numbers" practice which is so common.
So to answer your question, in C# it is usually a good idea to stick to int
unless:
- An automated code generator used a different value (like Entity Framework).
- All other developers on the project are aware that you are using the less common data types (include a comment pointing out that you used the data type and why).
- The less common data types are commonly used in the project already.
- The program requires the benefits of the less common data type (you have 100 million of these you need to keep in RAM, so the difference between a
byte
and an int
or an int
and a long
is critical, or the arithmetic differences of unsigned already mentioned).
If you need to do math on the data, stick to the common types.
Remember, you can cast from one type to another. This can be less efficient from a CPU stand point, so you are probably better off with one of the 7 common types, but it is an option if needed.
Enumerations (enum
) is one of my personal exceptions to the above guidelines. If I have only a few options, I will specify the enum to be a byte or a short. If I need that last bit in a flagged enum, I will specify the type to be uint
so I can use hex to set the value for the flag.
If you do use a property with value restricting code, be sure to explain in the summary tag what restrictions are there and why.
*C# aliases are used instead of .NET names like System.Int32
since this is a C# question.
Note: there was a blog or article from the .NET developers (which I cannot find), which pointed out the limited number of arithmetic functions and some reasons why they did not worry about it. As I remember, they indicated that they had no plans for adding support for the other data types.
Note: Java does not support unsigned data types and previously had no support for 8 or 16 bit whole numbers. Since many C# developers came from a Java background or needed to work in both languages, the limitations of one language would sometimes be artificially imposed on the other.