2.3 Type Basics
A C# program is best
understood in terms of
three basic elements: functions, data, and types. This book assumes
you have some programming experience, so let's start
with a brief overview of functions and data (which you should have
some familiarity with) and then move on to explain types in more
detail.
- Functions
-
A function performs
an
action by executing a series of statements. For example, you may have
a function that returns the distance between two points, or a
function that calculates the average of an array of values. A
function is a way of manipulating data.
- Data
-
Data is values that
functions operate on. For example, you may
have data holding the coordinates of a point, or data holding an
array of values. Data always has a particular type.
- Types
-
A type has a set of
data members and function members. The
function members are used to manipulate the data members. The most
common types are classes and structs, which provide a template for
creating data; data is always an instance of a type.
Types are quite an abstract concept, so let's look
at two concrete examples.
2.3.1 The String Class
The string class
specifies
a sequence of characters. This means you can store values such as
".NET" or
"http://oreilly.com". You can also
perform functions such as returning the character at a particular
position on the string or getting its lowercase representation.
In this example, we output the lower case representation of
".NET" (which will be
".net"), and return the length of
the string (which will be 4). To do this, we first create an instance
of a string, then use the ToLower method and
Length property, which are function members of
that string.
using System;
class Test {
static void Main ( ) {
string s = ".NET";
Console.WriteLine (s.ToLower( )); // outputs ".net"
Console.WriteLine (s.Length); // outputs 4
}
}
2.3.2 The int Struct
The int struct specifies
a signed integer (a positive or
negative whole number) that is 32 bits long. This means you can store
values ranging from -2,147,483,648 to 2,147,483,647 (or
-2n-1 to
2n-1-1, in which
n=32). With an int, you can perform functions
such as adding, multiplying, etc.
In this example, we output the result of multiplying 3 by 4. To do
this, we create two instances of the int, and then use the
* operator. The int type is
actually a built-in type that supports primitive arithmetic
functionality (such as *), but it is helpful to
think of the * operator as a function member of
the int type.
using System;
class Example {
static void Main ( ) {
int a = 3;
int b = 4;
Console.WriteLine (a * b);
}
}
2.3.3 A Custom Type
You can also define
custom types in
C#. In fact, a program is built by defining new types, each with a
set of data members and function members. In this example, we build
our own type, called Counter:
// Imports types from System namespace, such as Console
using System;
class Counter { // New types are typically classes or structs
// --- Data members ---
int value; // field of type int
int scaleFactor; // field of type int
// Constructor, used to initialize a type instance
public Counter(int scaleFactor) {
this.scaleFactor = scaleFactor;
}
// Method
public void Inc( ) {
value+=scaleFactor;
}
// Property
public int Count {
get {return value; }
}
}
class Test {
// Execution begins here
static void Main( ) {
// Create an instance of counter type
Counter c = new Counter(5);
c.Inc( );
c.Inc( );
Console.WriteLine(c.Count); // prints "10";
// create another instance of counter type
Counter d = new Counter(7);
d.Inc( );
Console.WriteLine(d.Count); // prints "7";
}
}
2.3.4 Type Instances
Generally, you must
create
instances of a type to use that type. Data members and function
members that require a type to be instantiated in order to be used
are called instance members (by default, members are instance
members). Data members and function members that can be used on the
type itself are called static members.
In this example, the instance method PrintName
prints the name of a particular panda, while the static method
PrintSpeciesName prints the name shared by all
pandas in the application (AppDomain):
using System;
class Panda {
string name;
static string speciesName = "Ailuropoda melanoleuca";
// Initializes Panda(See Instance Constructors)
public Panda(string n) {
name = n;
}
public void PrintName( ) {
Console.WriteLine(name);
}
public static void PrintSpeciesName( ) {
Console.WriteLine(speciesName);
}
}
class Test {
static void Main( ) {
Panda.PrintSpeciesName( ); // invoke static method
Panda p1 = new Panda("Petey");
Panda p2 = new Panda("Jimmy");
p1.PrintName( ); // invoke instance method
p2.PrintName( ); // invoke instance method
}
}
Note that the invocation of static members from outside of their
enclosing type requires specifying the type name. You may have
deduced that Console's
WriteLine method is a static member. It is
associated with the Console class, rather than an
instance of the Console class. A function member
should be static when it doesn't rely on any
instance data members. Similarly, the Main method
of all programs is a static member, which means that this method can
be called without instantiating the enclosing class.
2.3.5 Conversions
Each type has its own
set of
rules defining how it can be converted to and from other types.
Conversions between types may be implicit or explicit. Implicit
conversions can be performed automatically, while explicit
conversions require a cast:
int x = 123456; // int is a 4-byte integer
long y = x; // implicit conversion to 8-byte integer
short z =(short)x // explicit conversion to 2-byte integer
The rationale behind implicit conversions is they are guaranteed to
succeed and do not lose information. Conversely, an explicit
conversion is required either when runtime circumstances determine
whether the conversion will succeed or whether information may be
lost during the conversion.
Most conversion rules are supplied by the language, such as the
previously shown numeric conversions. Occasionally it is useful for
developers to define their own implicit and explicit conversions,
explained later in this chapter.
|