by kirupa |
1 January 2007Structs allow you to easily create
objects that store mixed data types. A strongly-typed
language such as C# provides many advantages, but let's say
you want to use an Array to store three pieces of
information: someone's first/last name and age. The names
will be stored as a string, and the age will be stored as an
integer. In a loosely-typed language such as ActionScript
2.0, you can get away with storing values of both string and
integer (number) into your array, but in C# your can
either store all strings or
store all integers. You cannot mix and match.
You can deal with this constraint by creating a
new data type that allows you to store
both strings and integers. You can create such a new data
type by using Structs!
-
Simple struct example.
-
Important things to keep in mind.
-
Using Properties
Let's start off by looking at a simple example that shows
how you use a struct and how to solve our mixed data type
conundrum I mentioned earlier. Using the example from the
intro, the following code creates a Person struct that
allows you to specify the first and last name as a string
and the age as an integer:
- public struct
Person
- {
- public
string
firstName;
- public
string
lastName;
- public
int
age;
- }
- class
Program
- {
- static
void
Main(string[]
args)
- {
- Person
homer;
- homer.firstName
=
"Homer";
- homer.lastName
=
"Simpson";
- homer.age
=
36;
- }
- }
Let's look at this code in detail, even though it is
pretty straightforward:
- public struct
Person
- {
- public
string
firstName;
- public
string
lastName;
- public
int
age;
- }
I declare a struct called Person, and within the Person
struct, declare three public variables of type string and
int. In order to use our struct to store Person information,
I use the following code from our Main method:
- Person
homer;
- homer.firstName
=
"Homer";
- homer.lastName
=
"Simpson";
- homer.age
= 36;
At the beginning of this article, I provided an example
where you can use a struct
to simulate storing mixed data types into an array. The
following code does just that:
- static
void
Main(string[]
args)
- {
- Person
homer
=
new Person();
- homer.FirstName
=
"Homer";
- homer.LastName
=
"Simpson";
- homer.Age
=
36;
-
- Person[]
foo
=
new Person[10];
- foo[0]
=
homer;
-
- Console.WriteLine("Person's
age is {0}", foo[0].Age);
- }
Notice that my List takes values of type Person, and that
is great because our Person struct stores values of types
string and int. We have achieved our goal of storing mixed
data types in C#!
The important things to keep in mind when using structs are:
- You are not required to define a a constructor.
Notice that my Person
struct does not contain a constructor, but you can use
one only if your constructor takes in parameters. You
cannot have a default constructor.
- When instantiating an object of type
struct, you do not need
to qualify your instantiation with the
new operator. For this
simple example, I declare a Person object called homer
as: Person homer;
As you will see, when using Properties in the next page,
you will need to use the
new
operator though.
- Structs can neither be inherited, nor can they be
set as the base for another class. But, you can
implement interfaces with structs though.
- On the surface, structs and classes seem very
similar. One major difference is in performance. Because
of the way structs are implemented (on the stack), they
are faster in many cases than classes which are
referenced on the heap.
There are other details that I will not cover in this
article, because explaining them would deviate too much from
other interesting things I want to explain, but you can read
about them in the MSDN documentation:
http://msdn2.microsoft.com/en-us/library/saxz13w4(VS.80).aspx
In my simple example, you access the public fields for your
struct instance directly. While that is an acceptable way to
store and retrieve data, they limit extensibility. When
writing programs, you want to try your best to add/change
functionality without breaking existing code.
When you access public fields directly, you are simply
retrieving a stored value. If you later decide to perform
some sort or processing instead of retrieving the raw data,
for example you want the age in days instead of years, such
a change may break parts of our application that depended
strictly on the earlier implementation. For a simple example
such as what you see here, re-writing some code is painless.
When you are working on a larger application, such bug fixes
can be time-consuming.
One solution to that problem is by bypassing public
fields and using Properties. Before I continue on, let me
provide you the code for our example using Properties:
- public
struct
Person
- {
- private
string
firstName;
- private
string
lastName;
- private
int
age;
-
- public
string
FirstName
- {
- get
- {
- return
firstName;
- }
- set
- {
- firstName
=
value;
- }
- }
- public
string
LastName
- {
- get
- {
- return
lastName;
- }
- set
- {
- lastName
=
value;
- }
- }
- public
int
Age
- {
- get
- {
- return
age;
- }
- set
- {
- age
=
value;
- }
- }
- }
- class
Program
- {
- static
void
Main(string[]
args)
- {
- Person
homer
=
new
Person();
- homer.FirstName
=
"Homer";
- homer.LastName
=
"Simpson";
- homer.Age
=
36;
-
- Console.WriteLine("Person's
first name is {0}",
homer.FirstName);
- }
- }
The functionality between my simple example and what is
shown above is the same. The difference is that while I can
easily extend my example using the Properties approach, it
will take some code rewriting to do the same in the simpler
example using public fields.
For example, the following is something that cannot be
done using the public field approach:
- public
int
Age
- {
- get
- {
- if
(age
>
30)
- {
- return
age
*
2;
- }
- else
- {
- return
age
/
2;
- }
- }
- set
- {
- age
=
value;
- }
- }
What is the great is that when you are using Properties,
you don't modify how you set or access any data from
the struct instance. I would set the age property as
homer.Age = 36, and I would get the age by accessing
homer.Age without the assignment ( = ) operator. The get/set
keywords take care of assigning or displaying values without
you doing anything differently.
The main takeaway message of this section is that you
should use Properties when you can, for even though it has a
higher initial cost, the benefits you gain from improved
extensibility and controlling access to an object's internal
state (encapsulation) is definitely worth it.
Onwards to the
next page!
|