- 5 -
Use of Properties - 116 -
Side Effects When Setting Values - 117 -
Static Properties - 119 -
Property Efficiency - 120 -
Chapter 19: Indexers - 120 -
Overview - 121 -
Indexing with an Integer Index - 121 -
Indexers and foreach - 125 -
Design Guidelines - 128 -
Chapter 20: Enumerators - 128 -
Overview - 128 -
A Line Style Enumeration - 128 -
Enumerator Base Types - 130 -
Initialization - 130 -
Bit Flag Enums - 131 -
Conversions - 131 -
Chapter 21: Attributes - 132 -
Overview - 132 -
Using Attributes - 133 -
An Attribute of Your Own - 136 -
Reflecting on Attributes - 138 -
Chapter 22: Delegates - 139 -
Overview - 140 -
Using Delegates - 140 -
Delegates as Static Members - 141 -
Delegates as Static Properties - 143 -
Chapter 23: Events - 145 -
Overview - 145 -
A New Email Event - 145 -
The Event Field - 147 -
Multicast Events - 147 -
Sparse Events - 147 -
Chapter 24: User-Defined Conversions - 149 -
Overview - 149 -
A Simple Example - 149 -
Pre- and Post- Conversions - 151 -
Conversions Between Structs - 152 -
Classes and Pre- and Post- Conversions - 157 -
Design Guidelines - 163 -
How It Works - 165 -
Chapter 25: Operator Overloading - 167 -
Overview - 167 -
Unary Operators - 167 -
Binary Operators - 167 -
An Example - 168 -
Restrictions - 169 -
Design Guidelines - 169 -
Chapter 26: Other Language Details - 169 -
Overview - 170 -
The Main Function - 170 -
Preprocessing - 171 -
Preprocessing Directives - 171 -
- 6 -
Lexical Details - 174 -
Chapter 27: Making Friends with the .NET Frameworks - 177 -
Overview - 177 -
Things All Objects Will Do - 177 -
Hashes and GetHashCode() - 179 -
Chapter 28: System.Array and the Collection Classes - 182 -
Overview - 182 -
Sorting and Searching - 182 -
Design Guidelines - 194 -
Chapter 29: Interop - 195 -
Overview - 196 -
Using COM Objects - 196 -
Being Used by COM Objects - 196 -
Calling Native DLL Functions - 196 -
Chapter 30: .NET Frameworks Overview - 196 -
Overview - 196 -
Numeric Formatting - 196 -
Date and Time Formatting - 204 -
Custom Object Formatting - 205 -
Numeric Parsing - 207 -
Using XML in C# - 208 -
Input/Output - 208 -
Serialization - 211 -
Threading - 214 -
Reading Web Pages - 215 -
Chapter 31: Deeper into C# - 217 -
Overview - 217 -
C# Style - 217 -
Guidelines for the Library Author - 217 -
Unsafe Code - 218 -
XML Documentation - 222 -
Garbage Collection in the .NET Runtime - 225 -
Deeper Reflection - 228 -
Optimizations - 234 -
Chapter 32: Defensive Programming - 234 -
Overview - 234 -
Conditional Methods - 234 -
Debug and Trace Classes - 235 -
Asserts - 235 -
Debug and Trace Output - 236 -
Using Switches to Control Debug and Trace - 238 -
Chapter 33: The Command Line - 243 -
Overview - 243 -
Simple Usage - 243 -
Response Files - 243 -
Command-Line Options - 243 -
Chapter 34: C# Compared to Other Languages - 246 -
Overview - 246 -
Differences Between C# and C/C++ - 246 -
Differences Between C# and Java - 248 -
Differences Between C# and Visual Basic 6 - 253 -
Other .NET Languages - 257 -
- 7 -
Chapter 35: C# Futures - 258 -
List of Figures - 258 -
Chapter 2: The .Net Runtime Environment - 258 -
Chapter 3: C# Quickstart - 258 -
Chapter 9: Structs (Value Types) - 258 -
Chapter 15: Conversions - 258 -
Chapter 16: Arrays - 258 -
Chapter 31: Deeper into C# - 258 -
List of Tables - 258 -
Chapter 30: .NET Frameworks Overview - 258 -
Chapter 33: The Command Line - 258 -
List of Sidebars - 258 -
Chapter 21: Attributes - 258 -
Table of Contents
A Programmer's Introduction to C#
Foreword
About This Book
Introduction
Chapter 1
- Object-Oriented Basics
Chapter 2
- The .Net Runtime Environment
Chapter 3
- C# Quickstart
Chapter 4
- Exception Handling
Chapter 5
- Classes 101
Chapter 6
- Base Classes And Inheritance
Chapter 7
- Class Member Accessibility
Chapter 8
- Other Class Stuff
Chapter 9
- Structs (Value Types)
Chapter 10
- Interfaces
Chapter 11
- Versioning Using new and override
Chapter 12
- Statements and Flow of Execution
Chapter 13
- Local Variable Scoping
Chapter 14
- Operators
Chapter 15
- Conversions
Chapter 16
- Arrays
Chapter 17
- Strings
Chapter 18
- Properties
Chapter 19
- Indexers
Chapter 20
- Enumerators
Chapter 21
- Attributes
Chapter 22
- Delegates
Chapter 23
- Events
Chapter 24
- User-Defined Conversions
Chapter 25
- Operator Overloading
Chapter 26
- Other Language Details
- 8 -
Chapter 27
- Making Friends with the .NET Frameworks
Chapter 28
- System.Array and the Collection Classes
Chapter 29
- Interop
Chapter 30
- .NET Frameworks Overview
Chapter 31
- Deeper into C#
Chapter 32
- Defensive Programming
Chapter 33
- The Command Line
Chapter 34
- C# Compared to Other Languages
Chapter 35
- C# Futures
Index
List of Figures
List of Tables
List of Sidebars
Back Cover
• Provides in-depth information about the functionality of the language
and C# “Quick Start”
• Shows you how to write components that fit seamlessly into the .NET
Frameworks
• Includes C# reference information tailored for C++, Java and Visual
Basic Programmers
• Suitable for intermediate to advanced developers and includes
coverage of advanced topics in C#
Eric Gunnerson, A member of the Microsoft C# design team, has written a
comprehensive C# tutorial addressed to the experienced programmer. A
Programmer’s Introduction to C# explains how C# works, why it was designed
the way it was, and how C# fits into Microsoft’s new .NET Frameworks. This
book teaches programmers how to write C# components and how to truly
leverage the power of the new .NET Runtime.
Gunnerson’s first chapters are for the impatient programmer. In them, he
provides an introduction to object-oriented programming with C# along with a
C# “Quick Start” for those who want a fast track to programming in C#. This is
followed by a more comprehensive section in which he uses his unique
insider’s view to explain each of the new C# language features in detail. He
covers fundamentals such as classes, structs, attributes, statements and flow
of execution, arrays, delegates and events, exception handling, and the
unique interoperability provided by the .NET Frameworks.
In the final portion of the book, Gunnerson provides a useful overview of the
.NET Frameworks. A section on the .NET Common Language Runtime and
Framworks shows how to write components that function well in the runtime
and how to use the basic runtime features (such as I/O). Gunnerson also
devoted time to more advanced topics such as regular expressions and
collections. Final chapters include Making Friends with the .NET Frameworks,
System.Array and the Collection Classes, .NET Fraeworks Overview, Deeper
into C# and Defensive Programming. Also included is a detailed C# language
comparison that will be indispensable for programmers currently working in
C++, Java, or Visual Basic.
All of the source code for this book in online at http://www.apress.com.
- 9 -
About the Author
Eric Gunnerson is a software design engineer in Microsoft’s Visual C++ QA
group and a member of the C# design team. In the course of his professional
career, he has worked primarily on database products and tools – and is
proud of the fact that nearly half of the companies he has worked for remain in
business.
A Programmer's Introduction to C#
ERIC GUNNERSON
Copyright ©2000 by Eric Gunnerson
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording, or by any information storage or retrieval
system, without the prior written permission of the copyright owner and the publisher. ISBN (pbk): 1-
893115-86-0
Printed and bound in the United States of America 2345678910
Trademarked names may appear in this book. Rather than use a trademark symbol with every
occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of
the trademark owner, with no intention of infringement of the trademark.
Editorial Directors: Dan Appleman, Gary Cornell, Karen Watterson
Technical Reviewers: David Staheli, Shawn Vita, Gus Perez, Jerry Higgins, Brenton Webster
Editor: Andy Carroll
Projects Manager: Grace Wong
Production Editor: Janet Vail
Page Compositor and Soap Bubble Artist: Susan Glinert
Artist: Karl Miyajima
Indexer: Nancy Guenther
Cover and Interior Design: Derek Yee Design
Distributed to the book trade in the United States by Springer-Verlag New York, Inc., 175 Fifth Avenue,
New York, NY, 10010 and outside the United States by Springer-Verlag GmbH & Co. KG, Tiergartenstr.
17, 69112 Heidelberg, Germany
In the United States, phone 1-800-SPRINGER orders@springer-ny.com ;
http://www.springer-ny.com
Outside the United States, contact orders@springer.de;
http://www.springer.de
; fax +49 6221 345229
For information on translations, please contact Apress directly at 901 Grayson Street, Suite 204,
Berkeley, CA, 94710 Phone: 510-549-5931; Fax: 510-549-5939; info@apress.com
;
http://www.apress.com
The information in this book is distributed on an “as is” basis, without warranty. Although every
precaution has been taken in the preparation of this work, neither the author nor Apress shall have any
liability to any person or entity with respect to any loss or damage caused or alleged to be caused
directly or indirectly by the information contained in this work.
Dedication
To Tony Jongejan, for introducing me to programming and being ahead of his time.
Acknowledgments
THOUGH WRITING A BOOK is often a lonely undertaking, no author can do it without help.
I’d like to thank all those who helped me with the book, including all those team members who
answered my incessant questions and read my unfinished drafts. I would also like to thank my
managers and Microsoft, both for allowing me to work on such a unique project and for allowing me to
write a book about it.
Thanks to the Apress team for making a bet on an unproven author and for not pestering me when I
waited to turn in content.
- 10 -
Thanks to all the artists who provided music to write to—all of which was commercially purchased—with
special thanks to Rush for all their work.
Finally, I’d like to thank all those who supported me at home; my wife Kim and daughter Samantha who
didn’t complain when I was working, even when it was during our vacation, and for my cat for holding
my arms down while I was writing.
Foreword
WHEN YOU CREATE a new programming language, the first question you’re asked invariably is,
why? In creating C# we had several goals in mind:
To produce the first component-oriented language in the C/C++ family. Software
engineering is less and less about building monolithic applications and more and more
about building components that slot into various execution environments; for example,
a control in a browser or a business object that executes in ASP+. Key to such
components is that they have properties, methods, and events, and that they have
attributes that provide declarative information about the component. All of these
concepts are first-class language constructs in C#, making it a very natural language in
which to construct and use components.
To create a language in which everything really is an object. Through innovative use of
concepts such as boxing and unboxing, C# bridges the gap between primitive types
and classes, allowing any piece of data to be treated as an object. Furthermore, C#
introduces the concept of value types, which allows users to implement lightweight
objects that do not require heap allocation.
To enable construction of robust and durable software. C# was built from the ground
up to include garbage collection, structured exception handling, and type safety. These
concepts completely eliminate entire categories of bugs that often plague C++
programs.
To simplify C++, yet preserve the skills and investment programmers already have. C#
maintains a high degree of similarity with C++, and programmers will immediately feel
comfortable with the language. And C# provides great interoperability with COM and
DLLs, allowing existing code to be fully leveraged.
We have worked very hard to attain these goals. A lot of the hard work took place in the C# design
group, which met regularly over a period of two years. As head of the C# Quality Assurance team,
Eric was a key member of the group, and through his participation he is eminently qualified to
explain not only how C# works, but also why it works that way. That will become evident as you
read this book.
I hope you have as much fun using C# as those of us on the C# design team had creating it.
Anders Hejlsberg
Distinguished Engineer
Microsoft Corporation
About This Book
C# IS ONE OF THE MOST EXCITING projects I’ve ever had the privilege to work on. There are
many languages with different strengths and weaknesses, but once in a while a new language
comes along that that meshes well with the hardware, software, and programming approaches of a
specific time. I believe C# is such a language. Of course, language choice is often a “religious
issue.”
[1]
I’ve structured this book as a tour through the language, since I think that’s the best and most
interesting way to learn a language. Unfortunately, tours can often be long and boring, especially if
the material is familiar, and they sometimes concentrate on things you don’t care about, while
overlooking things you’re interested in. It’s nice to be able to short-circuit the boring stuff and get
into the interesting stuff. To do that, there are two approaches you might consider:
To start things off quickly, there’s Chapter 3
, “C# QuickStart,” which is a quick overview of the
language, and gives enough information to start coding.
Chapter 34
, “C# Compared to Other Languages,” offers language-specific comparisons for C++,
VB, and Java for programmers attuned to a specific language, or for those who like to read
comparisons.
- 11 -
As I write this, it’s early August 2000, and the Visual Studio version that will contain C# has yet to
reach beta. The language syntax is fairly stable, but there will undoubtedly be some items changed
“around the edges.” See Chapter 35
, “C# Futures,” for some information on what is in store for the
future versions.
If you have comments about the book, you can reach me at gunnerso@halcyon.com
. All source
code can be downloaded from the Apress Web site at http://www.apress.com
.
[1]
See the Jargon File (//www.jargonfile.org ) for a good definition of "religious issue."
Introduction
Why Another Language?
AT THIS POINT, you’re probably asking yourself, “Why should I learn another language? Why not use
C++?” (or VB or Java or whatever your preferred language is). At least, you were probably asking
yourself that before you bought the book.
Languages are a little bit like power tools. Each tool has it’s own strengths and weaknesses. Though I
could use my router to trim a board to length, it would be much easier if I used a miter saw. Similarly, I
could use a language like LISP to write a graphics-intensive game, but it would probably be easier to
use C++.
C# (pronounced “C sharp”) is the native language for the .NET Common Language Runtime. It has
been designed to fit seamlessly into the .NET Common Language Runtime. You can (and, at times, you
should) write code in either Visual C++ or Visual Basic, but in most cases, C# will likely fit your needs
better. Because the Common Language Runtime is central to many things in C#, Chapter 2
, “The .NET
Runtime Environment,” will introduce the important parts of it—at least, those that are important to the
C# language.
C# Design Goals
When the C++ language first came out, it caused quite a stir. Here was a language for creating object-
oriented software that didn’t require C programmers to abandon their skills or their investment in
software. It wasn’t fully object-oriented in the way a language like Eiffel is, but it had enough object-
oriented features to offer great benefits.
C# provides a similar opportunity. In cooperation with the .NET Common Language Runtime, it provides
a language to use for component-oriented soft- ware, without forcing programmers to abandon their
investment in C, C++, or COM code.
C# is designed for building robust and durable components to handle real- world situations.
Component Software
The .NET Common Language Runtime is a component-based environment, and it should come as no
surprise that C# is designed to make component creation easier.
It’s a “component-centric” language, in that all objects are written as components, and the component is
the center of the action.
Component concepts, such as properties, methods, and events, are first-class citizens of the language
and of the underlying runtime environment. Declarative information (known as attributes) can be applied
to components to convey design- time and runtime information about the component to other parts of
the system. Documentation can be written inside the component and exported to XML.
C# objects don’t require header files, IDL files, or type libraries to be created or used. Components
created by C# are fully self-describing and can be used without a registration process.
C# is aided in the creation of components by the .NET Runtime and Frameworks, which provide a
unified type system in which everything can be treated as an object, but without the performance
penalty associated with pure object systems, such as Smalltalk.
- 12 -
Robust and Durable Software
In the component-based world, being able to create software that is robust and durable is very
important. Web servers may run for months without a scheduled reboot, and an unscheduled reboot is
undesirable.
Garbage collection takes the burden of memory management away from the programmer,
[1]
and the
problems of writing versionable components are eased by definable versioning semantics and the ability
to separate the interface from the implementation. Numerical operations can be checked to ensure that
they don’t overflow, and arrays support bounds checking.
C# also provides an environment that is simple, safe, and straightforward. Error handling is not an
afterthought, with exception handling being present throughout the environment. The language is type-
safe, and it protects against the use of variables that have not been initialized, unsafe casts, and other
common programming errors.
Real-World Software
Software development isn’t pretty. Software is rarely designed on a clean slate; it must have decent
performance, leverage existing code, and be practical to write in terms of time and budget. A well-
designed environment is of little use if it doesn’t provide enough power for real-world use.
C# provides the benefits of an elegant and unified environment, while still providing access to “less
reputable” features—such as pointers—when those features are needed to get the job done.
C# protects the investment in existing code. Existing COM objects can be used as if they were .NET
objects.
[2]
The .NET Common Language Runtime will make objects in the runtime appear to be COM
objects to existing COM-based code. Native C code in DLL files can be called from C# code.
[3]
C# provides low-level access when appropriate. Lightweight objects can be written to be stack allocated
and still participate in the unified environment. Low- level access is provided via the unsafe mode,
which allows pointers to be used in cases where performance is very important or when pointers are
required to use existing DLLs.
C# is built on a C++ heritage and should be immediately comfortable for C++ programmers. The
language provides a short learning curve, increased productivity, and no unnecessary sacrifices.
Finally, C# capitalizes on the power of the .NET Common Language Runtime, which provides extensive
library support for general programming tasks and application-specific tasks. The .NET Runtime,
Frameworks, and languages are all tied together by the Visual Studio environment, providing one-stop-
shopping for the .NET programmer.
[1]
It’s not that C++ memory management is conceptually hard; it isn’t in most cases, though there are some
difficult situations when dealing with components. The burden comes from having to devote time and effort to
getting it right. With garbage collection, it isn’t necessary to spend the coding and testing time to make sure
there aren’t any memory leaks, which frees the programmer to focus on the program logic.
[2]
Usually. There are details that sometimes make this a bit tougher in practice.
[3]
For C++ code, Visual C++ has been extended with “Managed Extensions” that make it possible to create
.NET components. More information on these extensions can be found on the Microsoft web site.
The C# Compiler and Other Resources
THERE ARE TWO WAYS of getting the C# compiler. The first is as part of the .NET SDK.
The SDK contains compilers for C#, VB, C++, and all of the frameworks. After you install the SDK, you
can compile C# programs using the csc command, which will generate an .exe that you can execute.
The other way of getting the compiler is as part of the Visual Studio.NET. The beta of Visual Studio.NET
will be available in the fall of 2000.
- 13 -
To find out more about getting the .NET SDK or the Visual Studio.NET beta, please consult this book’s
page on the Apress Web site at
http://www.apress.com
Compiler Hints
When compiling code, the C# compiler must be able to locate information about the components that
are being used. It will automatically search the file named mscorlib.dll , which contains the lowest-
level .NET entities, such as data types.
To use other components, the appropriate .dll for that component must be specified on the command
line. For example, to use WinForms, the system.winforms.dll file must be specified as follows:
csc /r:system.winforms.dll myfile.cs
The usual naming convention is for the .dll to be the same as the namespace name.
Other Resources
Microsoft maintains public newsgroups for .NET programming. The C# newsgroup is named
microsoft.public.dotnet.csharp.general , and it lives on the
msnews.microsoft.com news server.
There are numerous Web sites devoted to .NET information. Links to these resources also can be found
at the Apress Web site.
Chapter 1: Object-Oriented Basics
Overview
THIS CHAPTER IS AN INTRODUCTION to object-oriented programming. Those who are familiar with
object-oriented programming will probably want to skip this section.
There are many approaches to object-oriented design, as evidenced by the number of books written
about it. The following introduction takes a fairly pragmatic approach and doesn’t spend a lot of time on
design, but the design-oriented approaches can be quite useful to newcomers.
What Is an Object?
An object is merely a collection of related information and functionality. An object can be something that
has a corresponding real-world manifestation (such as an employee object), something that has some
virtual meaning (such as a window on the screen), or just some convenient abstraction within a program
(a list of work to be done, for example).
An object is composed of the data that describes the object and the operations that can be performed
on the object. Information stored in an employee object, for example, might be various identification
information (name, address), work information (job title, salary), and so on. The operations performed
might include creating an employee paycheck or promoting an employee.
When creating an object-oriented design, the first step is to determine what the objects are. When
dealing with real-life objects, this is often straightforward, but when dealing with the virtual world, the
boundaries become less clear. That’s where the art of good design shows up, and it’s why good
architects are in such demand.
Inheritance
Inheritance is a fundamental feature of an object-oriented system, and it is simply the ability to inherit
data and functionality from a parent object. Rather than developing new objects from scratch, new code
can be based on the work of other programmers
[1]
, adding only the new features that are needed. The
parent object that the new work is based upon is known as a base class, and the child object is known
as a derived class.
Inheritance gets a lot of attention in explanations of object-oriented design, but the use of inheritance
isn’t particularly widespread in most designs. There are several reasons for this.
- 14 -
First, inheritance is an example of what is known in object-oriented design as an “is-a” relationship. If a
system has an animal object and a cat object, the cat object could inherit from the
animal object, because a cat "is-a" animal. In inheritance, the base class is always more
generalized than the derived class. The cat class would inherit the eat function from the animal
class, and would have an enhanced sleep function. In real-world design, such relationships aren’t
particularly common.
Second, to use inheritance, the base class needs to be designed with inheritance in mind. This is
important for several reasons. If the objects don’t have the proper structure, inheritance can’t really work
well. More importantly, a design that enables inheritance also makes it clear that the author of the base
class is willing to support other classes inheriting from the class. If a new class is inherited from a class
where this isn’t the case, the base class might at some point change, breaking the derived class.
Some less-experienced programmers mistakenly believe that inheritance is “supposed to be” used
widely in object-oriented programming, and therefore use it far too often. Inheritance should only be
used when the advantages that it brings are needed
[2]
. See the coming section on “Polymorphism and
Virtual Functions.”
In the .NET Common Language Runtime, all objects are inherited from the ultimate base class named
object, and there is only single inheritance of objects (i.e., an object can only be derived from one
base class). This does prevent the use of some common idioms available in multiple-inheritance
systems such as C++, but it also removes many abuses of multiple inheritance and provides a fair
amount of simplification. In most cases, it’s a good tradeoff. The .NET Runtime does allow multiple
inheritance in the form of interfaces, which cannot contain implementation. Interfaces will be discussed
in Chapter 10
, "Interfaces."
Containment
So, if inheritance isn’t the right choice, what is?
The answer is containment, also known as aggregation. Rather than saying that an object is an
example of another object, an instance of that other object will be contained inside the object. So,
instead of having a class look like a string, the class will contain a string (or array, or hash table).
The default design choice should be containment, and you should switch to inheritance only if needed
(i.e., if there really is an “is-a” relationship).
[1]
At this point there should perhaps be an appropriate comment about standing “on the shoulders of
giants…”
[2]
Perhaps there should be a paper called “Multiple inheritance considered harmful.” There probably is one,
someplace.
Polymorphism and Virtual Functions
A while back I was writing a music system, and I decided that I wanted to be able to support both
WinAmp and Windows Media Player as playback engines, but I didn’t want all of my code to have to
know which engine it was using. I therefore defined an abstract class, which is a class that defines the
functions a derived class must implement, and that sometimes provides functions that are useful to both
classes.
In this case, the abstract class was called MusicServer, and it had functions like Play(),
NextSong(), Pause(), etc. Each of these functions was declared as abstract, so that each player
class would have to implement those functions themselves.
Abstract functions are automatically virtual functions, which allow the programmer to use polymorphism
to make their code simpler. When there is a virtual function, the programmer can pass around a
reference to the abstract class rather than the derived class, and the compiler will write code to call the
appropriate version of the function at runtime.
An example will probably make that clearer. The music system supports both WinAmp and Windows
Media Player as playback engines. The following is a basic outline of what the classes look like:
Không có nhận xét nào:
Đăng nhận xét