Sponsored Links

Basic .NET types

First things first: C# and VB.NET are strongly typed languages. That means the compiler must be absolutely certain of the type of an object at all times and types used in assignment to a variable or as parameters in a function must be of the same type or of a type inheriting from the expected type. If that is not the case then the compiler will throw an error.

There are two categories of type values: Reference types (classes) and Value types (structs). Both classes and structs can have methods and properties assigned to them so there doesn't need to be all that much difference between them if you don't want there to be. It's very important to know what you're working which you're working with at any one time though as it makes the difference between assignment to a variable causing a copy of the value to be assigned (as happens with Value types) and a copy of a reference to the object being assigned (as happens with a reference type)

Value Types

Value types are exactly what they sound like - types that store a specific value. Value types include data types you may well know more commonly as int, float, decimal, char etc, however those keywords actually refer to more technical structure names in the .NET framework.

Currently a full list of built-in value types exists here, but that link may be broken by the time you read this as Microsoft have an irritating habit of moving everything in MSDN around on a regular basis. The table below should give a brief list of the most common examples of value types.

Keyword .NET Struct Name Description
bool System.Boolean true or false
byte System.Byte 8 bit unsigned integer
char System.Char 16 bit Unicode character
short Int16 16 bit signed integer
int Int32 32 bit signed integer
long Int64 64 bit signed integer
float System.Single 32 bit floating-point number
double System.Double 64 bit floating-point number
decimal System.Decimal A decimal number
DateTime System.DateTime Date and time of day
TimeSpan System.TimeSpan Difference between two datetimes

Along with those types, there are various signed, unsigned and shortened variants that would be better off retrieved from MSDN than here. Also, when it comes to dealing with databases later on try not to forget that there are different data types for SQL values (e.g. System.Data.SqlTypes.SqlInt32), though these are most likely to be wrapped for you if you do things the ".net" way.

Whenever you work with a value type you gain access to all the methods associated with that datatype structure (again, these are best discovered using the MSDN .NET Framework library - just find the documentation for the type you're after, scroll down to the bottom of the page and click on the "Members" link to find a list of the methods supported by that data type). A good example of this is the DateTime data type which has a number of functions to make life easier for you, such as the "AddHours", "AddMinutes", "AddDays" etc. functions, which save all kinds of mathmatical grief you'd have had if the DateTime wasn't wrapped properly. As an aside, just remember that if you're doing maths with DateTime objects you'll probably get a TimeSpan back, not a DateTime.

You can also define your own value types by declaring structs. Structs are very similar to classes and are declared in a very similar fashion, even down to the inclusion of a constructor. You can even change a class into a struct by simply changing the keyword "class" to the keyword "struct". In theory you should use structs anywhere that a class logically represents a single value, will be less than 16 bytes, will not be changed after creation and will not be cast to a reference type.

Another value type you should be aware of is Enumerations. These are immensely handy for making code much more readable and limiting functions down to a pre-defined set of choices. An enumeration is quite simply a list of fixed values. In theory you can specify the underlying data type for an enumerations values but unless there is a compelling reason to do this you should avoid it as it is bad coding practice (if something needs to be assigned a specific value then it is unlikely that you want to use an enumeration and you should instead be using a class filled with constants of the appropriate type as that will better capture your requirements and promote better code maintainability).

You can declare an enumeration using the following syntax in C#: enum MyValues { Value1, Value2, Value3 }. If you absolutely must declare a type for the enumeration then use enum MyValues : int { Value1... .

If you use enumerations often enough you'll eventually want to loop through the list of values and do something with them. Use the "System.Enum" class to gain programmatic access to the members of an enumeration (e.g Enum.GetValues(typeof(MyValues));). Similarly you can use the Enum class to turn a value into a variable with the same type as the Enumeration using "Enum.Parse(typeof(MyValues), "Value1");".

Half way between the Reference and Value types

Here's where it gets a bit tricky: strings. Strings are technically reference types but the .net runtime treats them as value types. This is important since you don't pass around references to strings, you pass around string values but a string can be set to null. Other than that, it doesn't make much difference but it's definitely something important you should know. Part of the reason it's important is the performance hit it causes - it makes creation of strings and string operations more expensive. You should use a StringBuilder if you're building up a string gradually or as part of a loop (though be sensible - you only need it if you're doing more than say 5 string concatenations).

There's another "half-way house" exception here and that's the introduction of nullable value types which came in as part of .NET 2. This doesn't break any fundamental rules, it just wraps a value type in a class that can take a null value (for those that are interested, this is implemented using Generics by the Nullable<T> type). This is highly useful functionality however and is pretty easy to use right from the outset. If you want to declare a value type as nullable you can simply declare the type with a question mark after the type keyword (e.g int? x = null) in C#, otherwise you should declare the type as a Nullable generic in the normal way. The only problem this introduces is that you are no longer working with the basic value type, so if you want to do any operations that operate entirely on that basic value type you'll have to use the .Value property to get the basic, non-nullable type (obviously you'll need to check .HasValue first to make sure it's not null); Other than that though this should wrap the value type nicely for you and just add the ability to assign and check for null.

Reference Types

Reference types tend to be classes. As I mentioned earlier, assigning values to a variable that is a reference type causes that variable to store a pointer to that value and does not copy that value, hence any change you make to an object referenced from multiple places will be reflected in all the places that object is referenced from.

Reference types are generally created through use of a constructor on the class itself though sometimes you may have to invoke a function from a factory class in order to generate an instance of a specific type (remember: if a class is static you won't be able to create an instance of it).

I'm afraid describing the syntax of a class definition and what a constructor is sits outside the remit of this guide.

Arrays

Arrays are declared in C# using square brackets after a type declation (e.g int[] x;). To assign an initial set of values to an array simply declare a comma seperated list in curly braces (e.g int[] x = { 5, 6, 2 }). Arrays, like other .NET basic types, have an intrinsic set of functions and properties associated with them that are always available (these are the members of System.Array) including the Count property which will give you the length of an array and the Sort method, which sorts the array.

Exceptions

I'll cover error handling more later on, but it's worth noting that exceptions are also handled as reference types in the .NET framework and can be passed around and created like any other class.

Type Types

This is getting ahead of myself a bit, but sometimes you need to pass a type as a parameter to a function. If you happen to need to do this early in your life as a .net developer it's worth knowing that the compiler is actually looking for a class that represents the type, not just the keyword for that type. The syntax you need in order to handle types as programmatic objects is "typeof(typeKeyword)" (e.g. typeof(int) or typeof(string)). This will come in handy if you are specifying your own datatable structures.

Converting between Types

In general you can convert from one numeric type to another numeric type without worrying about it if you're converting to a type with higher precision (e.g. int to double), however you can't implicitly make the conversion the other way round.

There are a few options available to you if you want to convert between types but the method chosen will depend on the situation you're in. It may be that, for whatever reason, you've got an object stored as one type but you already know that it is an instance of a more specific type in which case all you have to do is cast the object to the type that you want it to be. In C# all you have to do to cast an object is put the type in brackets in front of the object name (e.g. object x = new DateTime(2008, 5, 1); DateTime adate = (DateTime)x;). This was much handier before generics came along but is still very useful to know.

If you need to take the value of one type and convert it to a different type that isn't simply a more accurate specification of that type then you need to convert the data. If that's the case then you can use System.Convert or you can call .ToString on the object and then call the .Parse or .TryParse functions of the type you're trying to convert to or you can use the cast operator.

Using the System.Convert class gives you a whole raft of overloaded functions that take a mutlitude of different types and pass out a value of the type you want to convert to. For example, if I had a char and I wanted to convert it to a byte I could call System.Convert.ToByte(myChar). It's fairly self explanatory, just type System.Convert. into Visual Studio and the autocomplete functionality should show you everything you need to know.

The form of conversion I find myself using most often is the TryParse method since generally I need to convert string values to other types. There are two functions on most numeric types that do basically the same thing; .Parse takes a string and converts it to the appropriate type and returns the value but it will throw an exception if it fails. .TryParse returns true of false depending on its success and returns the value of the conversion using an out parameter (e.g. string x = "5"; int y; bool convertSucceded = int.TryParse(x, out y); ). Since throwing exceptions is a performance hit you should use TryParse unless you are absolutely certain you won't encounter failed conversions.