Section 3.2. Types


3.2. Types

C# is a strongly typed language. That means that every object you create or use in a C# program must have a specific type (e.g., you must declare the object to be an integer or a string or a Dog or a Button). Essentially, the type indicates how big the object is (in memory) and what it can do.

Types come in two flavors: those that are built into the language (intrinsic types ) and those you create (classes and interfaces, discussed in Chapters 7 and 13). C# offers a number of intrinsic types, shown in Table 3-1.

Table 3-1. The intrinsic types

C# type

Size (in bytes)

.NET type

Description

byte

1

Byte

Unsigned (values 0-255).

char

2

Char

Unicode characters .

bool

1

Boolean

True or false.

sbyte

1

SByte

Signed (values -128 to 127).

short

2

Int16

Signed (short) (values -32,768 to 32,767).

ushort

2

UInt16

Unsigned (short) (values 0 to 65,535).

int

4

Int32

Signed integer values between -2,147,483,648 and 2,147,483,647.

uint

4

UInt32

Unsigned integer values between 0 and 4,294,967,295.

float

4

Single

Floating point number. Holds the values from approximately +/-1.5 * 10 -45 to approximately +/-3.4 * 10 38 with 7 significant figures.

double

8

Double

Double-precision floating point; holds the values from approximately +/-5.0 * 10 -324 to approximately +/-1.8 * 10 308 with 1516 significant figures.

decimal

12

Decimal

Fixed-precision up to 28 digits and the position of the decimal point. This is typically used in financial calculations. Requires the suffix "m" or "M."

long

8

Int64

Signed integers ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

ulong

8

UInt64

Unsigned integers ranging from 0 to approximately 1.85 * 10 19 .


Each type has a name (such as int ) and a size (such as 4 bytes). The size tells you how many bytes each object of this type occupies in memory. (Programmers generally don't like to waste memory if they can avoid it, but with the cost of memory these days, you can afford to be mildly profligate if doing so simplifies your program.) The description field of Table 3-1 tells you the minimum and maximum values you can hold in objects of each type.

Each C# type corresponds to an underlying .NET type. Thus, what C# calls an int , .NET calls an Int32 . This is interesting only if you care about sharing objects across languages.


Intrinsic types can't do much. You can use them to add two numbers together, and they can display their values as strings. User -defined types can do a lot more; their abilities are determined by the methods you create, as discussed in detail in Chapter 8.

Objects of an intrinsic type are called variables . Variables are discussed in detail later in this chapter.

3.2.1. Numeric Types

Most of the intrinsic types are used for working with numeric values ( byte , sbyte , short , ushort , int , uint , float , double , decimal , long , and ulong ).

The numeric types can be broken into two sets: unsigned and signed. An unsigned value ( byte , ushort , uint , ulong ) can hold only positive values. A signed value ( sbyte , short , int , long ) can hold positive or negative values, but the highest value is only half as large as the corresponding unsigned type. That is, a ushort can hold any value from 0 through 65,535, but a short can hold only -32,768 through 32,767. Notice that 32,767 is nearly half of 65,535 (it is off by one to allow for holding the value zero). The reason a ushort can hold up to 65,535 is that 65,535 is a round number in binary arithmetic (2 16 ).

Another way to categorize the types is into those used for integer values (whole numbers) and those used for floating-point values ( fractional or rational numbers). The byte , sbyte , ushort , uint , ulong , short , int , and long types all hold whole number values.

The byte and sbyte types are not used very often and won't be described in this book.


The double and float types hold fractional values. For most uses, float will suffice, unless you need to hold a really big fractional number, in which case you might use a double . The decimal value type was added to the language to support scientific and financial applications.

Typically, you decide which size integer to use ( short , int , or long ) based on the magnitude of the value you want to store. For example, a ushort can only hold values from 0 through 65,535, while a uint can hold values from 0 through 4,294,967,295.

That said, in real life, most of the time you'll simply declare your numeric variables to be of type int , unless there is a good reason to do otherwise . (Most programmers choose signed types unless they have a good reason to use an unsigned value. This is, in part, just a matter of tradition.)

Suppose you need to keep track of inventory for a book warehouse. You expect to house up to 40,000 or even 50,000 copies of each book. A signed short can only hold up to 32,767 values. You might be tempted to use an unsigned short (which can hold up to 65,535 values), but it is easier and preferable to just use a signed int (with a maximum value of 2,147,483,647). That way, if you have a runaway best seller, your program won't break (if you anticipate selling more than 2 billion copies of your book, perhaps you'll want to use a long !).

Throughout this book, we will use int wherever it works, even if short or byte might be workable alternatives. Memory is cheap, and programmer time expensive. There are circumstances where the difference in memory usage would be significant (for example, if you are going to hold a billion of them in memory), but we'll keep things simple by using the int type whenever possible.


float , double , and decimal offer varying degrees of size and precision. For most small fractional numbers, float is fine. Note that the compiler assumes that any number with a decimal point is a double unless you tell it otherwise. (The "Variables" section discusses how you tell it otherwise.)

3.2.2. Non-Numeric Types: char and bool

In addition to the numeric types, the C# language offers two other types: char and bool .

The char type is used from time to time when you need to hold a single character. The char type can represent a simple character ( A ), a Unicode character ( \u0041 ), or an escape sequence ( '\n' ). You'll see escape sequences later in this book, and their use will be explained in context.

The one remaining important type is bool , which holds a Boolean value. A Boolean value is one that is either true or false. Boolean values are used frequently in C# programming, as you'll see throughout this book. Virtually every comparison (is myDog bigger than yourDog ?) results in a Boolean value.

The bool type was named after George Boole (1815-1864), an English mathematician who published An Investigation into the Laws of Thought, on Which Are Founded the Mathematical Theories of Logic and Probabilities , and thus created the science of Boolean algebra.


3.2.3. Types and Compiler Errors

The compiler will help you by complaining if you try to use a type improperly. The compiler complains in one of two ways: it issues a warning or it issues an error.

You are well advised to treat warnings as errors . Stop what you are doing and figure out why there is a warning and fix the problem. Never ignore a compiler warning unless you are certain that you know exactly why the warning was issued and that you know something the compiler does not.

To have Visual Studio enforce this for you, follow these steps:

  1. Right-click on the project.

  2. Click on the Compile tab.

  3. Make sure the "Treat all warnings as errors" checkbox is checked or set the Warnings that you want to treat as errors using the drop-down boxes.


Programmers talk about design-time, compile-time, and runtime. Design-time is when you are designing the program, compile-time is when you compile the program, and runtime is (surprise!) when you run the program.

The earlier in your development process that you unearth a bug, the better. It is easier to fix a bug in your logic at design-time than to fix the bug once it has been written into code. Likewise, it is better (and cheaper) to find bugs in your program at compile-time than at runtime. Not only is it better; it is more reliable. A compile-time bug will fail every time you run the compiler, but a runtime bug can hide. Runtime bugs slip under a crack in your logic and lurk there (sometimes for months), biding their time, waiting to come out when it will be most expensive (or most embarrassing) to you.

It will be a constant theme of this book that you want the compiler to find bugs. The compiler is your friend (though I admit, at times it feels like your Nemesis). The more bugs the compiler finds, the fewer bugs your users will find.

A strongly typed language like C# helps the compiler find bugs in your code. Here's how: suppose you tell the compiler that Milo is of type Dog . Sometime later you try to use Milo to display text (calling the ShowText method). Oops, Dog s don't display text. Your compiler will stop with an error:

 Dog does not contain a definition for 'showText' 

Very nice. Now you can go figure out if you used the wrong object or you called the wrong method.

Visual Studio .NET actually finds the error even before the compiler does. When you try to add a method, IntelliSense pops up a list of valid methods to help you, as shown in Figure 3-1.

Figure 3-1. IntelliSense

When you try to add a method that does not exist, it won't be in the list. That is a pretty good clue that you are not using the object properly.



Learning C# 2005
Learning C# 2005: Get Started with C# 2.0 and .NET Programming (2nd Edition)
ISBN: 0596102097
EAN: 2147483647
Year: 2004
Pages: 250

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net