97041

Download as pdf or txt
Download as pdf or txt
You are on page 1of 81

Download the full version of the ebook at

https://ebookultra.com

C Precisely Second Edition Peter Sestoft

https://ebookultra.com/download/c-precisely-
second-edition-peter-sestoft/

Explore and download more ebook at https://ebookultra.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

C in a Nutshell 1st Edition Peter Prinz

https://ebookultra.com/download/c-in-a-nutshell-1st-edition-peter-
prinz/

ebookultra.com

C in a Nutshell 1st Edition Peter Drayton

https://ebookultra.com/download/c-in-a-nutshell-1st-edition-peter-
drayton/

ebookultra.com

Rabies Second Edition Alan C. Jackson

https://ebookultra.com/download/rabies-second-edition-alan-c-jackson/

ebookultra.com

Evaluating Contract Claims Second Edition R. Peter Davison

https://ebookultra.com/download/evaluating-contract-claims-second-
edition-r-peter-davison/

ebookultra.com
A New Land Law Second Edition Peter Sparkes

https://ebookultra.com/download/a-new-land-law-second-edition-peter-
sparkes/

ebookultra.com

Mathematical Techniques in GIS Second Edition Peter Dale

https://ebookultra.com/download/mathematical-techniques-in-gis-second-
edition-peter-dale/

ebookultra.com

Analysis of Longitudinal Data Second Edition Peter Diggle

https://ebookultra.com/download/analysis-of-longitudinal-data-second-
edition-peter-diggle/

ebookultra.com

Survival Math for Marketers 1st Edition Peter C. Weiglin

https://ebookultra.com/download/survival-math-for-marketers-1st-
edition-peter-c-weiglin/

ebookultra.com

Psycho Oncology Second Edition Jimmie C. Holland

https://ebookultra.com/download/psycho-oncology-second-edition-jimmie-
c-holland/

ebookultra.com
C Precisely Second Edition Peter Sestoft Digital Instant
Download
Author(s): Peter Sestoft, Henrik I. Hansen
ISBN(s): 9780262516860, 0262516861
Edition: second edition
File Details: PDF, 6.64 MB
Year: 2011
Language: english
public static IEnumerable<R> Scan<A,R>(this IEnumerable<A> xs, Func<R,A,R> f, R e)
{ public static IEnumerable<R> Scan<A,R>(this IEnumerable<A> xs, Func<R,A,R> f, R e)
yield return e; {
public static IEnumerable<R> Scan<A,R>(this IEnumerable<A> xs, Func<R,A,R> f, R e)
yield return e;
foreach (var x in xs) { foreach (var x in xs) {{ yield return e;
foreach (var x in xs) {
e = f(e, x); e = f(e, x); e = f(e, x);
yield return e; yield return e;
yield return e; } }
} }
}
}

Peter Sestoft and Henrik I. Hansen


second edition
C# Precisely

}
C# Precisely
Second Edition
Peter Sestoft
Henrik I. Hansen

C# Precisely
Second Edition

The MIT Press


Cambridge, Massachusetts
London, England

c 2012 Massachusetts Institute of Technology

All rights reserved. No part of this book may be reproduced in any form by any electronic or mechanical
means (including photocopying, recording, or information storage and retrieval) without permission in
writing from the publisher.

This book was set in Times by the authors using LATEX.

Printed and bound in the United States of America.

Library of Congress Cataloging-in-Publication Data

Sestoft, Peter.
C# precisely / Peter Sestoft and Henrik I. Hansen. — 2nd ed.
p. cm.
Includes bibliographic references and index.
ISBN 978-0-262-51686-0 (pbk.: alk. paper)
1. C# (Computer program language) I. Hansen, Henrik I. II. Title.
QA76.73.C154S47 2012
005.133—dc23 2011021052

10 9 8 7 6 5 4 3 2 1
Contents ix

28 Linq, Language Integrated Query (C# 3.0) 194


28.1 Linq Expressions (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
28.2 The Query Expression Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
28.3 Differences between Linq and SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
28.4 Auxiliary Interfaces That Support Linq (C# 3.0) . . . . . . . . . . . . . . . . . . . . . 200
28.5 Extension Methods on IEnumerable<T> (C# 3.0) . . . . . . . . . . . . . . . . . . . . . 202
28.6 Numeric Extension Methods on IEnumerable<T> (C# 3.0) . . . . . . . . . . . . . . . . 208
28.7 Extension Methods on IOrderedEnumerable<T> (C# 3.0) . . . . . . . . . . . . . . . . 208
28.8 Extension Methods on Non-generic Enumerable (C# 3.0) . . . . . . . . . . . . . . . . 209
28.9 Static Methods to Generate Enumerables (C# 3.0) . . . . . . . . . . . . . . . . . . . . 209

29 Namespaces 210
29.1 The using Directive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

30 Partial Type Declarations 212

31 Assertions and the Debug.Assert Method 214

32 Attributes 216
32.1 Some Predefined Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
32.2 Declaring and Using Custom Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . 216

33 Main Differences between C# and Java 218

34 Resources 220

Index 221
Contents
Preface xi

Notational Conventions xii

1 Compiling, Loading, and Executing C# Programs 2


1.1 Source Files and Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Names and Reserved Names 4

3 C# Naming Conventions 4

4 Comments and Program Layout 4

5 Data and Types 6


5.1 Value Types and Simple Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
5.2 Reference Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.3 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

6 Variables, Parameters, Fields, and Scope 14


6.1 Scope of Variables, Parameters, and Members (Including Fields) . . . . . . . . . . . . . 14
6.2 Default Values and Definite Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.3 Local var Declarations: Compile-Time Type Inference (C# 3.0) . . . . . . . . . . . . . 16
6.4 The Type dynamic: Run-Time Resolution of Calls and More (C# 4.0) . . . . . . . . . . 16

7 Strings 18
7.1 String Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.2 String Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

8 String Builders 26

9 Arrays 28
9.1 One-Dimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
9.2 Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
9.3 Class Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

10 Classes 34
10.1 Class Declarations and Class Bodies . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
10.2 Class Modifiers abstract, sealed, static . . . . . . . . . . . . . . . . . . . . . . . 36
10.3 Member Access Modifiers private, protected, internal, public . . . . . . . . . . 36
10.4 Subclass, Base Class, Inheritance, and Hiding . . . . . . . . . . . . . . . . . . . . . . . 38
10.5 Field Declarations in Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
10.6 Constant Declarations in Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
10.7 Method Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
vi Contents

10.8 Method Modifiers static new virtual override sealed abstract . . . . . . . . . . 44


10.9 Extension Methods (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
10.10 Optional or Default-Value Method Parameters (C# 4.0) . . . . . . . . . . . . . . . . . . 46
10.11 Constructor Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
10.12 Static Field Initialization and the Static Constructor . . . . . . . . . . . . . . . . . . . . 48
10.13 Member Classes or Nested Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.14 Class Access Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
10.15 Property Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
10.16 Indexer Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
10.17 Operator Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
10.18 User-Defined Conversion Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10.19 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

11 The Machine Model: Stack, Heap, and Garbage Collection 58


11.1 Class and Object versus Struct Type and Struct Value . . . . . . . . . . . . . . . . . . . 58

12 Expressions 60
12.1 Table of Expression Forms and Predefined Operators . . . . . . . . . . . . . . . . . . . 60
12.2 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
12.3 The checked and unchecked Operators . . . . . . . . . . . . . . . . . . . . . . . . . . 62
12.4 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
12.5 Bitwise Operators and Shift Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
12.6 Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
12.7 Assignment Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
12.8 Conditional Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
12.9 Object Creation Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
12.10 Object Initializer (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
12.11 Collection Initializers (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
12.12 Struct Value Creation Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
12.13 Instance Test Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
12.14 Instance Test and Cast Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
12.15 Field Access Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
12.16 The Current Object Reference this . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
12.17 Method Call Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
12.18 Property Access Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
12.19 Indexer Access Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
12.20 Type Cast Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
12.21 The typeof Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
12.22 Anonymous Method Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
12.23 Lambda Expressions (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
12.24 Anonymous Object Expressions (C# 3.0) . . . . . . . . . . . . . . . . . . . . . . . . . 92
12.25 Implicitly Typed Array Creation Expressions (C# 3.0) . . . . . . . . . . . . . . . . . . 92
Contents vii

13 Statements 94
13.1 Expression Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.2 Block Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.3 The Empty Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.4 Declaration Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
13.5 Choice Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
13.6 Loop Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
13.7 Returns, Labeled Statements, Exits, and Jumps . . . . . . . . . . . . . . . . . . . . . . 102
13.8 Throwing and Catching Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
13.9 The checked and unchecked Statements . . . . . . . . . . . . . . . . . . . . . . . . . 108
13.10 The using Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
13.11 The lock Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
13.12 The yield Statement and Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

14 Struct Types 112


14.1 Boxing of Struct Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
14.2 The this Reference in a Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
14.3 Struct Expressions: Value or Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

15 Interfaces 116
15.1 Interface Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
15.2 Classes and Struct Types Implementing Interfaces . . . . . . . . . . . . . . . . . . . . 118
15.3 Explicit Interface Member Implementations . . . . . . . . . . . . . . . . . . . . . . . . 118

16 Enum Types 120

17 Delegate Types 122

18 Type dynamic (C# 4.0) 124

19 Nullable Types over Value Types 126

20 Exceptions 128

21 Threads, Concurrent Execution, and Synchronization 130


21.1 Threads and Concurrent Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
21.2 Locks and the lock Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
21.3 Operations on Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
21.4 Operations on Locked Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

22 Task Parallel Library (C# 4.0) 136


22.1 Class Parallel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
22.2 The Task Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

23 Asynchronous Methods: async and await (C# 5.0) 142


viii Contents

24 Mathematical Functions 144

25 Input and Output 146


25.1 Creating Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
25.2 Overview of Input and Output Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 148
25.3 Using Declarations, Exceptions, Thread Safety . . . . . . . . . . . . . . . . . . . . . . 148
25.4 Sequential Character Input: TextReaders . . . . . . . . . . . . . . . . . . . . . . . . . 150
25.5 Sequential Character Output: TextWriters . . . . . . . . . . . . . . . . . . . . . . . . . 152
25.6 Binary Input and Output: BinaryReader and BinaryWriter . . . . . . . . . . . . . . . . 154
25.7 Byte Input and Output: Stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
25.8 Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
25.9 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
25.10 Network Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

26 Generic Types and Methods 164


26.1 Generics: Safety, Generality, and Efficiency . . . . . . . . . . . . . . . . . . . . . . . . 164
26.2 Generic Types, Type Parameters, and Constructed Types . . . . . . . . . . . . . . . . . 164
26.3 Generic Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
26.4 Constraints on Type Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
26.5 Generic Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
26.6 How Can Type Parameters Be Used? . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
26.7 Generic Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
26.8 Generic Delegate Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
26.9 Abbreviations for Constructed Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
26.10 Generic Struct Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
26.11 The Implementation of Generic Types and Methods . . . . . . . . . . . . . . . . . . . 176
26.12 Variance of Type Parameters (C# 4.0) . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

27 Generic Collections: Sets, Lists, and Dictionaries 180


27.1 The ICollection<T> Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
27.2 Enumerators and Enumerables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
27.3 Comparables, Equatables, Comparers, and EqualityComparers . . . . . . . . . . . . . . 184
27.4 The IList<T> Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
27.5 The IDictionary<K,V> Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
27.6 The List<T> Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
27.7 The Dictionary<K,V> and SortedDictionary<K,V> Classes . . . . . . . . . . . . . . . 190
27.8 The KeyValuePair<K,V> Struct Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
27.9 The ISet<T> Interface and the HashSet<T> and SortedSet<T> Classes . . . . . . . . . 190
27.10 The Queue<T> Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
27.11 The Stack<T> Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Preface
This second edition of C# Precisely describes the programming language C# (pronounced “c sharp”),
versions 3.0, 4.0, and 5.0. It is a quick reference for readers who have already learned or are learning C#
from a standard textbook and who want to know the language in more detail. It should be particularly
useful for readers who know the Java programming language and who want to learn C#.
C# is a class-based single-inheritance object-oriented programming language designed for the Com-
mon Language Runtime of Microsoft’s .Net platform, a managed execution environment with a type-safe
intermediate language and automatic memory management. Thus C# is similar to the Java programming
language in many respects, but it is different in almost all details. In general, C# favors programmer
convenience over language simplicity. It was designed by Anders Hejlsberg and others from Microsoft
Corporation.
C# includes many useful features not found in Java: struct types, operator overloading, reference pa-
rameters, rectangular multidimensional arrays, user-definable conversions, properties and indexers (styl-
ized methods), and delegates (methods as values), but it omits Java’s inner classes and Java’s wildcards in
generic types. See section 33 for a summary of the main differences.
C# may appear similar to C++, but its type safety is much better and its machine model is very different
because of managed execution and garbage collection. In particular, there is no need to write destructors
and finalizers nor to aggressively copy objects or keep track of object ownership.
This book presents C# version 4.0 as used in Microsoft Visual Studio 2010, including lambda expres-
sions, extension methods, anonymous object expressions, object initializers, collection initializers, local
variable type inference, type dynamic, type parameter covariance and contravariance, and not least, Linq
(language integrated query). In addition, it describes asynchronous programming as found in C# 5.0.
Of Microsoft’s .Net Framework class libraries, only threads, input-output, generic collection classes, and
parts of the Task Parallel Library are covered. The book does not cover unsafe code, destructors, finaliza-
tion, reflection, preprocessing directives (#define, #if, . . . ), details of IEEE 754 floating-point numbers
or expression trees.
General rules of the language are given on left-hand pages, and corresponding examples are shown
on the facing right-hand pages for easy reference. All examples are fragments of legal C# programs,
available at <http://www.itu.dk/people/sestoft/csharpprecisely/>. For instance, the code for example 17
is found in file Example017.cs.

Acknowledgments: Thanks to a stay at Microsoft Research in Cambridge, England, we could exper-


iment with a very early version of generics in C# in 2001. Later, the .Net Framework Alpha Program
provided an early implementation of all C# 2.0 features, and Ecma International provided C# standards
documents. Special thanks to Andrew Kennedy, Don Syme, Claudio Russo, and Simon Peyton-Jones
for directly or indirectly making this possible. The Mono project developers provided another neat C#
compiler and run-time environment, and rapid bug fixes. Thanks to Hans Dybkjær, Jørgen Steensgaard-
Madsen, Joe Kiniry, Jon Jagger, and Niels Peter Svenningsen for comments and suggestions on draft
manuscripts, and to Carsten Jørgensen, Lawrence Berg, Ken Friis Larsen, and Morten Boysen for correc-
tions to the published book. It was a pleasure to work with Robert Prior, Ada Brunstein, Mel Goldsipe,
and Alice Cheyer at the MIT Press.

xi
Notational Conventions
Symbol Meaning
a expression or value of array type
b expression or value of boolean type
C class
D delegate type
e expression
E exception type or event name
f field
g group of items (Linq)
i expression or value of integer type
I interface type
M method
N namespace
o expression or value of object type
P property name
s expression of type string
S struct type
sig signature of method or constructor
t type name or type expression (simple type or value type or reference type)
T, U type parameters (generic types and methods)
u expression or value of thread type
v value of any type
x, y variable or parameter or field or array element or range variable (Linq)
xs, ys stream of items, such as an enumerable (Linq)

In this book, fragments of the C# grammar are presented using an informal notation, with non-terminal
symbols such as class-declaration in italics, terminal symbols such as class in typewriter font, and
metavariables such as C for class names and M for method names.
A complete and detailed grammar for C# can be found in the official language specification (see
section 34). The complete grammar is not included here because it runs to more than 30 dense pages and
yet is too general: many well-formedness requirements must be expressed as additional side conditions
on the grammar.

xii
C# Precisely
2 Compiling, Loading, and Executing C# Programs

1 Compiling, Loading, and Executing C# Programs


Running a C# program involves three stages: compilation (which first checks that the C# program is well-
formed and then generates intermediate code, also called bytecode), loading (which loads and checks the
bytecode and then generates machine code), and execution (which runs the machine code).

1.1 Source Files and Compilation


A C# program consists of one or more source files (with filename suffix .cs). A source file may contain
one or more type declarations: classes, interfaces, struct types, enum types, and delegate types.
Before a C# program can be executed, it must be compiled and loaded. The C# compiler, such
as Microsoft’s csc or the Mono project’s mcs, checks that the program conforms to the syntax for C#
programs, that operators (such as +) are applied to the correct type of operands (such as 5 and x), and so
on. If this is the case, the compiler generates a module or file containing intermediate code.
A module resulting from compilation may be an executable Prog.exe if it contains a static method
Main() or Main(String[]) but not both, or a library Prog.dll, or a raw module Prog.netmodule.
An assembly consists of one or more modules, exactly one of which must be an executable (.exe)
or a library (.dll). An assembly has a manifest with version number and other metadata, so it can be
deployed on its own; a raw module cannot. A raw module can be added to an assembly as an external
module using the /addmodule compile option when generating the assembly. The assembly can access
both internal and public members (section 10.14) of the module. The module remains a separate file.
An assembly may be made to refer to another assembly by using the /reference compile option
when generating the referring assembly. A reference to the .Net class library mscorlib.dll is included
by default. The referring assembly can access only public members of the referred-to assembly.

Compiler Option Short Form Meaning


/target:exe /t:exe Compile to an executable (.exe) file, the default
/target:library /t:library Compile to a library (.dll) file
/target:module /t:module Compile to a module (.netmodule) file
/reference:Lib.dll /r:Lib.dll Include reference to library Lib
/addmodule:M1.netmodule Include module M1.netmodule in assembly
/main:MyClass /m:MyClass Method Main in class MyClass is the entry point
/debug Add debugging information
/define:DEBUG /d:DEBUG Enable assertions (section 31)

1.2 Execution
An executable file Prog.exe compiled from program Prog.cs can be (loaded and) executed by typing
its name on the command line or by explicitly invoking the run-time system. This will execute the static
method Main() or Main(String[] args) in Prog.cs, in the latter case binding the command line argu-
ments arg1, arg2, . . . to the array elements args[0], args[1], . . . (see examples 1 and 2).
The /main compiler option can be used to specify the entry point: the class whose Main method must
be executed after loading an executable.
Compiling, Loading, and Executing C# Programs 3

Example 1 Complete Program in File Example001.cs


Almost all programs need the using System directive (section 29.1) but it is omitted in later examples.
using System;
public class Sum {
static void Main(String[] args) {
int sum = 0;
for (int i=0; i<args.Length; i++)
sum += int.Parse(args[i]);
Console.WriteLine("The sum is " + sum);
}
}

Example 2 Compiling and Running a Program from the Command Line


This example shows how to compile the file Example001.cs from the command line under Windows
using Microsoft .Net (left) and under Linux or Windows using the Mono system (right). In both cases the
program outputs the text: The sum is 29.
csc Example001.cs mcs Example001.cs
Example001 7 9 13 mono Example001.exe 7 9 13

Example 3 Compiling an Executable with an External Module and Reference to a Library


First compile file Mod.cs into a raw module Mod.netmodule and compile Lib.cs into a library Lib.dll.
Then compile the file Prog.cs and create an executable Prog in file Prog.exe that has external module
Mod and refers to the library Lib. Finally, run the executable Prog.exe:
csc /target:module Mod.cs
csc /target:library Lib.cs
csc /addmodule:Mod.netmodule /reference:Lib.dll Prog.cs
Prog

The resulting assembly consists of two files: the main file Prog.exe, and file Mod.netmodule which
contains the external module. The assembly has a manifest with version number, other metadata, and
references to two other assemblies: the library Lib, and mscorlib which is included by default.

Assembly Assembly Assembly


Prog.exe file Lib.dll file mscorlib.dll

Manifest Mod.netmodule file Manifest Manifest

Module Module Module Module


Prog.exe Mod.netmodule Lib.dll mscorlib.dll
4 Comments and Program Layout

2 Names and Reserved Names


A legal name of a variable, parameter, method, field, indexer, property, class, struct, enum, delegate,
interface, or namespace starts with a letter or an underscore (_) and continues with zero or more letters or
underscores or digits (0–9). Uppercase letters and lowercase letters are considered distinct. A legal name
cannot be one of the following keywords, which are reserved names:
abstract as base bool break byte case catch char checked class const continue decimal
default delegate do double else enum event explicit extern false finally fixed float
for foreach goto if implicit in int interface internal is lock long namespace new
null object operator out override params private protected public readonly ref return
sbyte sealed short sizeof stackalloc static string struct switch this throw true try
typeof uint ulong unchecked unsafe ushort using virtual void volatile while
To use a keyword as a name, prefix it with the @ character, as in int @while = 17. The pseudo-keywords
add, alias, ascending, by, descending, from, get, global, group, into, join, let, orderby,
partial, remove, select, set, value, where, and yield are reserved only in certain contexts.

3 C# Naming Conventions
The following naming conventions are often followed, although not enforced by the C# compiler:
• If a name is composed of several words, then each word (except possibly the first one) begins with
an uppercase letter. Examples: currentLayout, LayoutComponent.
• Names of local variables, parameters, and private or protected fields begin with a lowercase letter.
Examples: vehicle, currentVehicle. Avoid using lowercase letter l or uppercase letter O as
names.
• Names of public or internal instance fields, static fields, and named constants begin with an upper-
case letter. Examples: Vehicle, MaxValue.
• Names of classes, methods, events, properties, and enum types begin with an uppercase letter.
Examples: Cube, ColorCube.
• Names of interfaces begin with the letter I followed by an uppercase letter. Example: IEnumerable.
• A namespace name usually is a dot-separated sequence of names, each of which begins with an
uppercase letter (System or System.Text or System.Text.RegularExpressions), but could also
be a reverse domain name (dk.itu.c5 or ch.cern.mathlib).

4 Comments and Program Layout


A comment has no effect on the execution of the program but is used to help humans understand the
program. It may be inserted anywhere whitespace is permitted. There are two forms: one-line comments
and delimited comments. Do not insert a delimited comment in the middle of a line, as in example 5.
Program layout has no effect on the computer’s execution of the program but is used to help humans
understand the structure of the program. For reasons of space the recommended layout style is not always
followed in the rest of the book.
Comments and Program Layout 5

Example 4 Using Keywords as Identifier Names


This feature is provided for interoperability with other programming languages, in which class or public
may be a perfectly legal name for a field or method; it should not be used in ordinary C# programming.
Note that for non-keywords such as i, the identifier @i is the same as i.
class School {
const int @class = 2004;
const bool @public = true;
String @delegate = "J. Smith ";
public static int @double(int i) { return 2 * @i; }
}
...
School school = new School();
Console.WriteLine([email protected]() + " " + School.@class);

Example 5 A One-Line Comment, a Delimited Comment, and Abuse of a Delimited Comment


class Comment {
// This is a one-line comment; it extends to the end of the line
/* This is a delimited comment,
extending over several lines.
*/
int /* This delimited comment extends over part of a line */ x = 117;
}

Example 6 Program Layout Style


class LayoutExample { // Class declaration
int j;

LayoutExample(int j) {
this.j = j; // One-line body
}

int Sum(int b) { // Multiline body


if (j > 0) { // If statement
return j + b; // Single statement
} else if (j < 0) { // Nested if-else, block statement
int res = -j + b;
return res * 117;
} else { // j == 0 // Terminal else, block statement
int sum = 0;
for (int i=0; i<10; i++) // For loop
sum += (b - i) * (b - i);
return sum;
}
}
}
6 Data and Types

5 Data and Types


A type is a set of data values and operations on them. Every variable, parameter, and field has a declared
type, every method has a declared return type, and so on. The compiler will infer a type for every expres-
sion based on this information. This compile-time type determines which operations can be performed on
the value of the expression.
Types are used in declarations of local variables; in declarations of classes, interfaces, struct types,
and their members; in delegate types; in object and array creation expressions (sections 9 and 12.9); in
type cast expressions (section 12.20); and in instance test expressions (section 12.13).
A type is either a value type (section 5.1) or a reference type (section 5.2).

5.1 Value Types and Simple Types


A value type is either a simple type (this section), a struct type (section 14), or an enum type (section 16).
A variable of value type directly contains a value of that type, not just a reference to it. Assigning a value
of value type to a variable or field or array element of value type makes a copy of the value.
A simple type is either bool or one of the numeric types. A numeric type is a signed or unsigned
integer type, including the character type, or a floating-point type, or the fixed-point type decimal which
is useful for exact calculations such as financial accounting. The tables opposite show the simple types,
some example constants, value range, kind, and size (in bytes). For escape sequences such as \u0000 in
character constants, see section 7. Integer constants may be written in decimal or hexadecimal notation:
Notation Base Distinction Example Integer Constants
Decimal 10 1234567890, 0127, -127
Hexadecimal 16 Leading 0x 0x12ABCDEF, 0x7F, -0x7F
Two’s complement representation is used for the signed integer types (sbyte, short, int, and long).
The integer types are exact. The floating-point types are inexact and follow the IEEE 754 floating-point
standard, with the number of significant digits indicated opposite.
For each simple type there is a predefined struct type (in the System namespace), also shown opposite.
The simple type is an alias for the struct type and has these members:
• int.Parse(String s) of type int is the integer obtained by parsing s (example 1). It throws
ArgumentNullException if s is null, FormatException if s cannot be parsed as an integer, and
OverflowException if the parsed number cannot be represented as an int. All simple types have
similar Parse methods. The floating-point Parse methods are culture-sensitive (section 7.2).
• The smallest and greatest possible values of each numeric type are represented by constant fields
MinValue and MaxValue, such as int.MinValue and int.MaxValue.
• The float and double types define several constants: double.Epsilon is the smallest number
of type double greater than zero, double.PositiveInfinity and double.NegativeInfinity
represent positive and negative infinity, and double.NaN is a double value that is not a number.
These values are determined by the IEEE 754 standard.
• The decimal type defines the constants MinusOne, Zero, and One of type decimal along with
methods for computing with and converting numbers of type decimal.
Data and Types 7

Example 7 Three Equivalent Declarations of an Integer Variable


using System;
...
int i1;
Int32 i2;
System.Int32 i3;

Simple Types: Constants, Default Values, and Ranges


Type Example Constants Default Value Range (MinValue. . . MaxValue)
bool true false false, true
char ’A’, ’\u0041’ ’\u0000’ ’\u0000’ . . . ’\uFFFF’
sbyte -119 0 −128 . . .127
byte 219 0 0 . . . 255
short -30319 0 −32768 . . .32767
ushort 60319 0 0 . . . 65535
int -2111222319 0 −2147483648 . . .2147483647
uint 4111222319 0 0 . . . 4294967295
long -411122319L 0 −9223372036854775808 . . .9223372036854775807
ulong 411122319UL 0 0 . . . 18446744073709551615
float -1.99F, 3E8F 0.0 ±10−44 . . . ± 1038, 7 significant digits
double -1.99, 3E8 0.0 ±10−323 . . . ± 10308, 15–16 significant digits
decimal -1.99M 0.0 ±10−28 . . . ± 1028, 28–29 significant digits (*)
(*) May be changed to range ±10 −6143 . . . ± 10 6144 and 34 significant digits (IEEE 754 decimal128).

Simple Types: Kind, Size, and Struct Name


Type Alias Kind Size Struct Type
bool Logical 1 System.Boolean
char Unsigned integer 2 System.Char
sbyte Integer 1 System.SByte
byte Unsigned integer 1 System.Byte
short Integer 2 System.Int16
ushort Unsigned integer 2 System.UInt16
int Integer 4 System.Int32
uint Unsigned integer 4 System.UInt32
long Integer 8 System.Int64
ulong Unsigned integer 8 System.UInt64
float Binary floating-point 4 System.Single
double Binary floating-point 8 System.Double
decimal Decimal floating-point 16 System.Decimal
When t is one of these types, then sizeof(t) is a compile-time constant expression whose value is Size.
8 Data and Types

5.2 Reference Types


A reference type is a class, an interface, an array type, or a delegate type. A class is defined by a class
declaration (section 10), an interface is defined by an interface declaration (section 15), and a delegate
type is defined by a delegate declaration (section 17). Array types are discussed in section 9.
A variable of reference type either contains the special value null or a reference to an object or array
or delegate that is allocated in the heap. The special value null does not refer to anything. The constant
null, denoting the null value, can have any reference type. Assigning a reference value to a reference
variable assigns only the reference and does not copy the object or array or delegate pointed to.
Types are organized in a type hierarchy, as shown opposite, with class Object as the base class of all
other types. The methods implemented by these top classes are inherited by their derived types.

Class Object is the base class (superclass) of all classes. Let o1 and o2 be expressions of type Object:
• o1.Equals(o2) returns true if o1 and o2 are equal; otherwise false. By default, values of reference
type are equal if created by the same execution of new; but (for example) class String overrides
Equals to compare the string contents instead (section 7), and class ValueType overrides Equals
so that two values of a struct type are equal if all their fields are equal.
• Object.ReferenceEquals(o1, o2) returns true if both o1 and o2 are null, or if both refer to the
same object or array or delegate; otherwise false. False also if any of o1 or o2 has value type.
• Object.Equals(o1, o2) returns true if Object.ReferenceEquals(o1, o2) or o1.Equals(o2)
does; otherwise false. This is inefficient for arguments of value type that get boxed and then com-
pared using o1’s Equals method.
• o1.GetType() returns the unique object of class Type that represents the run-time type of o1.
• o1.GetHashCode() returns a hash code for o1 as an int, useful when o1 is used as a key in a hash
table (section 27.7). Subclasses should override this method so that (1) if o1 and o2 are equal by
Equals, then they have the same hash code; (2) modifications to o1 do not change its hash code;
(3) the hash codes should be uniformly distributed; and (4) the method should be fast and must not
throw exceptions. All simple types and class String have appropriate GetHashCode methods.
• o1.ToString() returns a human-readable culture-sensitive representation of the object o1.
Class String is a frequently used subclass of Object and is a reference type (section 7).
Class Array is a subclass of Object and the base class of all array types such as int[] (section 9).
Class ValueType is a subclass of Object and the base class of all value types, including the simple types,
the struct types, and the enum types. It is not itself a value type. If v1 and v2 have a struct type (that
derives from ValueType) then v1.Equals(v2) uses reflection to compare the fields of v1 and v2 using
Equals. This can be slow, so struct types should override Equals. Also, struct types that have modifiable
fields should override GetHashCode; the default method may be unsuitable for such struct types.
Class Enum is a subclass of ValueType and the base class of all enum types (section 16) but is not itself
an enum type. It implements enum-specific methods inherited by all enum types.
Class Delegate is a subclass of Object and the base class of all delegate types (section 17) but is not itself
a delegate type. It implements delegate-specific methods inherited by all delegate types.
Data and Types 9

Example 8 Methods Declared in Class Object


The methods declared in class Object are inherited by all types and therefore can be used on all values
(unless the methods are hidden by a declaration in a subclass).

Object o1 = new Object(), o2 = new Object(), o3 = o1;


Console.WriteLine(o1.Equals(o3) + " " + o1.Equals(o2)); // True False
Console.WriteLine(o1.GetHashCode() == o3.GetHashCode()); // True
Console.WriteLine(o1.GetHashCode() == o2.GetHashCode()); // Usually False
Console.WriteLine(o1.GetHashCode() + " " + o2.GetHashCode()); // Usually distinct
Console.WriteLine(o1.GetType()); // System.Object
String s1 = "abc", s2 = "ABC", s3 = s1 + "";
Console.WriteLine(s1.Equals(s3) + " " + s1.Equals(s2)); // True False
Console.WriteLine(s1.GetHashCode() == s3.GetHashCode()); // True
Console.WriteLine(s1.GetHashCode() == s2.GetHashCode()); // Usually False
Console.WriteLine(s1.GetHashCode() + " " + s2.GetHashCode()); // Usually distinct
Console.WriteLine(s1.GetType()); // System.String
Console.WriteLine(117.GetHashCode()); // 117
Console.WriteLine(5.GetType()); // System.Int32
Console.WriteLine(5.0.GetType()); // System.Double
int[] ia1 = { 7, 9, 13 }, ia2 = { 7, 9, 13 };
Console.WriteLine(ia1.GetType()); // System.Int32[]
Console.WriteLine(ia1.Equals(ia2)); // False
Console.WriteLine(Object.ReferenceEquals(ia1,ia2)); // False
Console.WriteLine(ia1.GetHashCode() == ia2.GetHashCode()); // Usually False
int[,] ia3 = new int[6,7];
Console.WriteLine(ia3.GetType()); // System.Int32[,]
int[][] ia4 = new int[6][];
Console.WriteLine(ia4.GetType()); // System.Int32[][]

Top Layers of the Type Hierarchy


All these types are from the System namespace.

Class Object

...
Class String Class Array Class ValueType Class Delegate other classes

... ...
array types delegate types
Class Enum

... ... ...


simple types enum types struct types
10 Data and Types

5.3 Conversion
For a given type ts there may exist an implicit or explicit conversion of a value of type ts into a value of
another type tt. If there is an implicit conversion from type ts to type tt, then an expression of type ts
can be used wherever an expression of type tt is expected. In particular, any value v of type ts may be
bound to a variable or field or parameter x of type tt, for instance, by the assignment x = v.
If there is an explicit conversion from ts to tt, then a cast expression (section 12.20) can be used to
obtain a value of type tt from the value of type ts.

5.3.1 Standard Conversions between Simple Types


The standard conversions between simple types are shown in the table below. There are standard conver-
sions between all the simple types except bool.
A conversion marked I is an implicit conversion (no cast required), and one marked E is an explicit
conversion (cast required). More precisely, an implicit conversion marked I cannot lose precision, whereas
one marked IL may lose precision; neither can throw an exception.
An explicit conversion marked ER rounds the source value and so may lose precision or produce an
infinity, but it throws no exception. An explicit conversion marked ET truncates the source value to the
nearest integral number (rounds towards zero); in a checked context (section 12.3) it throws OverflowEx-
ception if the result is too large, and in an unchecked context it produces an unspecified value in the target
type. An explicit conversion marked ED rounds the source value, and throws OverflowException if the
source value is too large or is a NaN.
Finally, an explicit conversion marked EB works on the bit pattern representing the source value.
In a checked context (section 12.3) the conversion throws OverflowException if the source value is not
representable in the target type. In an unchecked context no exception is thrown. Instead, if the source
type is larger than the target type (in bits; see page 7), the excess most significant bits are discarded from
the source value. If the source type is smaller than the target type, the source value is padded (extended
with most significant bits) to fit the target type, padding with the sign bit if the source type is signed, and
padding with zeros if it is unsigned.

Source Type Target Type (tt)


(ts) char sbyte byte short ushort int uint long ulong float double decimal
char I EB EB EB I I I I I I I I
sbyte EB I EB I EB I EB I EB I I I
byte EB EB I I I I I I I I I I
short EB EB EB I EB I EB I EB I I I
ushort EB EB EB EB I I I I I I I I
int EB EB EB EB EB I EB I EB IL I I
uint EB EB EB EB EB EB I I I IL I I
long EB EB EB EB EB EB EB I EB IL IL I
ulong EB EB EB EB EB EB EB EB I IL IL I
float ET ET ET ET ET ET ET ET ET I I ED
double ET ET ET ET ET ET ET ET ET ER I ED
decimal ET ET ET ET ET ET ET ET ET ER ER I
Data and Types 11

Example 9 Conversions between Simple Types

double d = 2.9;
Console.WriteLine((int)d); // ET double-->int; prints 2
Console.WriteLine((int)(-d)); // ET double-->int; prints -2
uint seconds = (uint)(24 * 60 * 60); // EB int-->uint
double avgSecPerYear = 365.25 * seconds; // I uint-->double
float f = seconds; // IL uint-->float
long nationalDebt1 = 14349539503882;
double perSecond = 45138.89;
decimal perDay = // ED double-->decimal
seconds * (decimal)perSecond; // I uint-->decimal
double nd2 = nationalDebt1 + (double)perDay; // ER decimal-->double
long nd3 = (long)nd2; // ET double-->long
float nd4 = (float)nd2; // ER double-->float

Summary of Standard Implicit Conversions between Simple Types


If there is a thick-line path from a type ts to a type tt, then ts is implicitly convertible to tt. If there is
any path from a type t to a type u, then t is better than u in overloading resolution (section 12.17.1).

double

decimal

float

ulong

long

uint

int

ushort

short char

byte

sbyte
12 Data and Types

5.3.2 Standard Conversions between Reference Types or Type Parameters


If ts and tt are types, then a standard implicit conversion from ts to tt exists in these cases:
• ts is a reference type and tt is the class Object; or
• ts and tt are class types or interface types, and ts is derived from tt (section 10.4); or
• ts is a class type and tt is an interface implemented by ts or one of its base classes; or
• ts and tt are array types with the same number of dimensions, their element types are reference
types, and there is an implicit conversion from the element type of ts to the element type of tt; or
• ts is an array type and tt is Array, or ts is a delegate type and tt is Delegate; or
• ts is t[] and tt is IList<t> or IList<u> with an implicit reference conversion from t to u; or
• ts is the type of the null expression and tt is a reference type or a nullable type (section 19); or
• ts is a type parameter (section 26.2) and tt a type bound for that parameter.
If ts and tt are types, then a standard explicit conversion from ts to tt exists in these cases:
• ts is the class Object and tt is a reference type; or
• ts and tt are class types, and tt is derived from ts; or
• ts is a non-sealed class type and tt is an interface, and ts does not implement tt; or
• ts is an interface and tt is a class type, and tt is not sealed or else tt implements ts; or
• ts and tt are interfaces and ts does not implement tt; or
• ts and tt are array types with the same number of dimensions, their element types are reference
types, and there is an explicit conversion from the element type of ts to the element type of tt; or
• tt is an array type and ts is Array, or tt is a delegate type and ts is Delegate; or
• ts is IList<t> and tt is u[] and there is an implicit conversion from u[] to IList<t>; or
• tt is a type parameter (section 26.2) and ts a type bound for that parameter.
A standard implicit or explicit conversion from one reference type to another does not change the given
reference value, nor does it produce a new one; only the compile-time type of the reference is affected.

5.3.3 Boxing and Unboxing Conversions


A standard boxing conversion is an implicit conversion from a value type ts to Object or to an interface
type tt implemented by ts. A boxing conversion creates a copy of the value in the heap, including an
indication of its type ts (see section 14.1). This permits values of simple types and struct types to be
stored in non-generic collections. However, generic collections should be preferred for type safety and
efficiency (section 26).
An unboxing conversion is an explicit conversion (tt)v from a reference v of type Object or interface
type ts to a value type tt that implements ts. An unboxing conversion first tests whether the type stored
in the boxed object v is tt. If this is not so, or if v is null, it throws InvalidCastException; otherwise it
copies the value out of v.

5.3.4 User-Defined Conversions


A class or struct type may declare implicit and explicit conversions for that type (section 10.18).
Data and Types 13

Example 10 Conversions between Reference Types


This example shows the cases of implicit and explicit reference conversions listed in section 5.3.2. The
explicit conversions are performed using type cast expressions (section 12.20).
interface I1 { }
interface I2 : I1 { }
interface J { }
class B : I2 { }
class C : B, J { }
delegate void D(String s);
...
Object b1 = new B(); // Implicit B-->Object
I2 b2 = new B(); // Implicit B-->I2
B c1 = new C(); // Implicit C-->B
I1 b3 = b2; // Implicit I2-->B
I1[] i2a1 = new I2[5]; // Implicit I2[]-->I1[]
Array inta1 = new int[5]; // Implicit int[]-->Array
Delegate d1 = new D(Print); // Implicit D-->Delegate
C n = null; // Implicit null type-->C
B b4 = (B)b1; // Explicit Object-->B
C c2 = (C)c1; // Explicit B-->C
J b5 = (J)c1; // Explicit C-->J
B b6 = (B)b2; // Explicit I2-->B
I1 i2 = (I1)b2; // Explicit I2-->I1
I2[] i2a2 = (I2[])i2a1; // Explicit I1[]-->I2[]
int[] inta2 = (int[])inta1; // Explicit Array-->int[]
D d2 = (D)d1; // Explicit Delegate-->D

Example 11 Boxing and Unboxing Conversions


interface I { void Print(); }
struct S : I {
public int i;
public S(int i) { this.i = i; }
public void Print() { Console.WriteLine(i); }
}
...
int i = 7;
Object o = i; // Implicit boxing int-->Object
int j = 5 + (int)o; // Explicit unboxing Object-->int
S s1 = new S(11);
I s2 = s1; // Implicit boxing S-->I
s1.i = 22;
s1.Print(); // 22
s2.Print(); // 11
S s3 = (S)s2; // Explicit unboxing I-->S
s3.Print(); // 11
14 Variables, Parameters, Fields, and Scope

6 Variables, Parameters, Fields, and Scope


A variable is declared inside a method body, constructor body, property body, indexer body, or another
block statement (section 13.2). The variable can be used only in that block statement, and only after it has
been declared. A parameter is a special kind of variable: it is declared in the parameter list of a method,
constructor, or indexer, and can be used only in that method or constructor or indexer. A field is declared
inside a class or struct, but not inside a method or constructor or initializer block of the class.
A variable, parameter, or field of simple type holds a value of that type, such as the boolean false, the
integer 117, the floating-point number 1.7, or a value of struct type (section 14). A variable, parameter, or
field of reference type t either has value null or holds a reference to an object or array or delegate.

6.1 Scope of Variables, Parameters, and Members (Including Fields)


The scope of a name is that part of the program in which the name can be used unqualified. The scope
of a variable extends from just after its declaration to the end of the innermost enclosing block statement.
The scope of a parameter of a method or constructor or operator or indexer is the entire function body.
The scope of a variable declared in the header of a for statement is the entire statement (header and
body). The scope of the control variable in a foreach statement is the body only:
for (int x = ...; ...; ...) body
foreach (int x in ...) body
The scope of a variable or parameter x cannot contain a redeclaration of x. However, the scope of a class
or struct member (such as a field x) may contain a declaration of a variable x that shadows the field, but
only if the member has not been used in the same block prior to the declaration of the variable (see M3
and M4 in example 12). The scope of a member is the entire class, except where shadowed by a variable
or parameter of the same name. The member can be used anywhere in the class, also textually before its
declaration. If the member is public or protected, its scope includes subclasses, except where hidden
by a subclass member of the same name. The scope of a static member also includes every nested class,
except where shadowed by a member of the nested class, but it excludes subclasses of the nested class.

6.2 Default Values and Definite Assignment


For every type t there is a default value, which can be produced by the expression default(t). For a
simple type t the default value is shown on page 7. For a struct type t the default value is a struct whose
fields have their default values. For a reference type t the default value is null. For an enum type the
default value is that of its underlying representation type. For a nullable type t? the default value is null.
A field of an object or struct is automatically initialized with the default value for its type t.
Unlike a field, a variable or out parameter is not given an initial value. Instead the compiler requires
that a variable be definitely assigned wherever its value is used. That is, regardless of what conditional
statements or loops have been executed between the declaration of a variable and a use of its value, the
variable must have been assigned a value before its use.
Like a variable, an out parameter (section 10.7) must have been definitely assigned, in the function
that declares it, whenever its value is used. On the other hand, a by-value parameter or ref parameter is
always given a value when the function is called, and so is always definitely assigned.
Variables, Parameters, Fields, and Scope 15

Example 12 Scope of Fields, Parameters, and Variables


This program declares five variables or fields, all called x, and shows where each one is in scope. The
field and the variables are labeled #1, . . . , #5 for reference only.

class Scope {
void M1(int x) { // Declaration of parameter x (#1); shadows x (#5)
x = 7; // x #1 in scope; legal, but no effect outside M1
} //
void M3() { //
int x; // Declaration of variable x (#2); shadows x (#5)
x = 7; // x #2 in scope
}
void M4() { //
x = 7; // x #5 in scope
// int x; // Would be ILLEGAL, giving a new meaning to x
}
void M5() { //
{ //
int x; // Declaration of variable x (#3); shadows x (#5)
x = 7; // x #3 in scope
} //
{ //
int x; // Declaration of variable x (#4); shadows x (#5)
x = 7; // x #4 in scope
} //
}
public int x; // Declaration of field x (#5)
}

Example 13 Definite Assignment


Variable x is definitely assigned at (#1) below because it gets assigned regardless of which branch of the
if statement is executed, but y is not, because it gets assigned in only one of the branches. Variable z is
not definitely assigned at (#3) because it will be assigned only if the body of the for loop gets executed
(and the compiler does not take the value of variables in loop conditions into account when determining
that).

int x, y, z;
if (args.Length == 0)
x = y = 10;
else
x = args.Length;
Console.WriteLine(x); // x definitely assigned, y and z not (#1)
y = x;
for (int i=0; i<y; i++) // x and y definitely assigned, z not (#2)
z = i;
// Console.WriteLine(z); // z still not definitely assigned! (#3)
16 Variables, Parameters, Fields, and Scope

6.3 Local var Declarations: Compile-Time Type Inference (C# 3.0)


The var keyword may be used in a local variable declaration (section 13.4) to tell the compiler that the
type of the declared variable should be inferred from the given expression:
var identifier = expression;

The expression (section 12) must have a compile-time type and hence cannot be an anonymous method
(section 12.22), a lambda expression (section 12.23), or the null literal. The declared variable is given
the type inferred for the expression as if that type had been explicitly stated; subsequent uses of, or
assignments to, the variable do not affect this type inference process. The variable remains statically
typed as if the type had been explicitly given.
The var keyword may be used also in for statements (section 13.6.1), foreach statements (sec-
tion 13.6.2), and using statements (section 13.10). It cannot be used for declaration of fields, method
parameters, or method return types; their types must always be given explicitly. Since var is not a type
but a keyword that declares a variable using compile-time type inference, var also cannot be used in casts,
as array element type, as type parameter in generic types, and so on.

6.4 The Type dynamic: Run-Time Resolution of Calls and More (C# 4.0)
With type dynamic, one can obtain behavior very similar to that of dynamically typed programming
languages such as Clojure, Groovy, Javascript (Jscript), Python, Ruby, Scheme, and others.
If an expression has type dynamic, then a method call, operator application, delegate call, or field
access involving that expression will be resolved dynamically at run-time rather than at compile-time. This
means that almost any such expression will be accepted by the compiler but may fail with an exception at
run-time.
Whereas var is a keyword, dynamic is a type. Hence, unlike var, dynamic can be used for fields,
method parameters, and method return types as well as in constructed types such as dynamic[] and
List<dynamic>.
Run-time resolution of method calls, operator applications, delegate applications, and field accesses
produces exactly the same result as compile-time resolution would produce. In those cases where compile-
time resolution would fail (causing the compiler to reject the program), run-time resolution will instead
throw an exception (typically RuntimeBinderException) at run-time. Thus the run-time system repli-
cates the compiler’s resolution machinery for this purpose. Since compile-time operations are moved to
run-time, where they may be executed repeatedly, operations involving expressions of type dynamic are
slower than those resolved at compile-time; in extreme cases, up to ten times slower. Nevertheless, run-
time resolution is convenient when calling external dynamic applications such as Microsoft Excel or web
browsers.
The run-time resolution machinery is called the Dynamic Language Runtime but is actually a set of
libraries built on top of the ordinary .NET run-time system.
More information and more examples using type dynamic are found in sections 12.17.8 and 18.
Variables, Parameters, Fields, and Scope 17

Example 14 Compile-Time Inference of Local Variable Types

var x = 0.0; // Inferred type double


var b = false; // Inferred type bool
var ps = new List<int>(); // Inferred type List<int>
ps.Add(2); ps.Add(3); ps.Add(5);

Example 15 Compile-Time Resolution and Checking of Operators, Assignments, and Field Accesses

class Phone {
public readonly String name;
public readonly int phone;
public Phone(String name, int phone) { ... }
}
...
var d1 = 34; // Inferred type int
int i1 = d1 * 2; //
int i2 = (int)d1 * 2; // Cast (int)d1 succeeds at compile-time
// bool b1 = d1; // Rejected at compile-time
// d1 = true; // Rejected at compile-time
var p1 = new Phone("Kasper", 5170);
String s1 = p1.name; // Field access checked only at compile-time
// int n1 = p1.age; // Field access rejected at compile-time
var p2 = new { name = "Kasper", phone = 5170 };
String s2 = p2.name; // Field access checked only at compile-time
// int n2 = p2.age; // Field access rejected at compile-time

Example 16 Run-Time Resolution of Assignments and Field Accesses


Contrast this with example 15. For anonymous objects, see section 12.24.

dynamic d1 = 34;
int i1 = d1 * 2; // OK: cast (int)(d1*2) at run-time
int i2 = (int)d1 * 2; // OK: cast (int)d1 at run-time
// bool b1 = d1; // Compiles OK; cast (bool)d1 throws at run-time
d1 = true; // OK
bool b2 = d1; // OK: cast (bool)d1 succeeds at run-time
dynamic p1 = new Phone("Kasper", 5170);
String s1 = p1.name; // Field access checked at run-time
// int n1 = p1.age; // Compiles OK; field access throws at run-time
dynamic p2 = new { name = "Kasper", phone = 5170 };
String s2 = p2.name; // Field access checked at run-time
// int n2 = p2.age; // Compiles OK; fields access throws at run-time
18 Strings

7 Strings
A string is an object of the predefined class String from namespace System. The keyword string is
an alias for System.String. A string constant is a sequence of characters within double quotes, such
as "New York", "B52", or the empty string "". Internally, a character is stored as a number using the
Unicode character encoding, whose character codes 0–127 coincide with the ASCII character encoding.
String constants and character constants may use character escape codes:
Escape Code Meaning
\a Alert (bell)
\b Backspace
\t Horizontal tab
\v Vertical tab
\n New line
\f Form feed (page break)
\r Carriage return
\" The double quote character
\’ The single quote character
\\ The backslash character
\0 The NUL character (ASCII or Unicode 0)
\xd The character whose character code is the hexadecimal number d
\xdd The character whose character code is the hexadecimal number dd
\xddd The character whose character code is the hexadecimal number ddd
\xdddd The character whose character code is the hexadecimal number dddd
\udddd The character with four-digit hexadecimal Unicode encoding dddd
\Udddddddd The character with eight-digit hexadecimal Unicode encoding dddddddd
A character escape sequence represents a single character. Since the letter A has code 65 (decimal), which
is written 41 in hexadecimal, the string constant "A\x41\u0041\U00000041" is the same as "AAAA". The
\Udddddddd escape code can be used only in string constants, not in character constants.
A verbatim string constant is a string constant prefixed with the @ character. Any escape sequence in
such a string denotes itself, just like ordinary characters, except that "" denotes the double quote character.
Let s1 and s2 be expressions of type String:
• s1.ToString() simply returns s1 itself, and somewhat surprisingly, so does s1.Clone(), whereas
String.Copy(s1) produces a new String object containing the same sequence of characters as s1.
• s1.Length of type int is the length of s1, that is, the number of characters in s1.
• s1[i] of type char is the character at position i in s1, counting from 0. If the index i is less than 0,
or greater than or equal to s1.Length, then the exception IndexOutOfRangeException is thrown.
• s1.Equals(s2) of type bool is true if both s1 and s2 are non-null and contain the same sequence
of characters. Uppercase and lowercase characters are considered distinct.
• s1 == s2 is true if both s1 and s2 are null, or if both are non-null and s1.Equals(s2); and the
inequality s1 != s2 has the same meaning as !(s1 == s2). Hence s1 != "" is true when s1 is
a non-empty string, but also when s1 is null.
Strings 19

Example 17 Regular String Constants and Verbatim (@) String Constants


Console.WriteLine("\u0041BC"); // ABC
Console.WriteLine(@"\u0041BC"); // \u0041BC
Console.WriteLine("Say \"Hello\"!"); // Say "Hello"!
Console.WriteLine(@"Say ""Hello""!"); // Say "Hello"!
String s1 = @"Line 1
and Line 2"; // Newline allowed only in verbatim string
String s2 = "Line 1\nand Line 2"; // s1 and s2 are equal

Example 18 Equality of Strings


The comparison operator == applied to arguments of type String compares the contents of the strings: the
character sequences. When applied to arguments of type Object, it compares the object references. Two
strings that contain the same character sequences may be represented by a single String object (s1 and
s2) if they are compile-time constants; otherwise they need not be (s2 and s4).
String s1 = "abc", s2 = "ab" + "c", s3 = null; // Compile-time constants
String s4 = args[0]; // Value given at run-time
// Assume command line argument args[0] is "abc" so s4 is "abc":
Console.WriteLine(s1==s2); // True
Console.WriteLine((Object)s1==(Object)s2); // Probably True
Console.WriteLine(s2==s4); // True
Console.WriteLine((Object)s2==(Object)s4); // Probably False
Console.WriteLine("{0} {1} {2}", s3==s1, s3!=s1, s3==s3); // False True True

Example 19 Counting the Number of e’s in a String Using a String Indexer


static int eCount(String s) {
int ecount = 0;
for (int i=0; i<s.Length; i++)
if (s[i] == ’e’)
ecount++;
return ecount;
}

Example 20 Concatenating All Command Line Arguments


When concatenating many strings, do not use += but a string builder (section 8 and example 31).
public static void Main(String[] args) {
String res = ""; // Inefficient
for (int i=0; i<args.Length; i++) // Inefficient
res += args[i]; // Inefficient
Console.WriteLine(res);
}

Example 21 The + Operator Is Left Associative


Console.WriteLine(10 + 25 + "A"); // Same as (10 + 25) + "A", that is, "35A"
Console.WriteLine("A" + 10 + 25); // Same as ("A" + 10) + 25, that is, "A1025"
20 Strings

7.1 String Methods


Let s1, s2, and s3 be expressions of type String, let cs be an expression of type char[], and let v be an
expression of any type:

• String.Compare(s1, s2) returns a negative integer, zero, or a positive integer, according as s1


precedes, equals, or follows s2 in the lexicographical ordering based on the Unicode character
encoding and the culture of the current thread. The null reference precedes any non-null string.
• String.Compare(s1, s2, ignoreCase) works similarly, but does not distinguish lowercase and
uppercase if ignoreCase is true.
• s1.CompareTo(s2) has the same meaning as String.Compare(s1, s2) when s1 is not null.
• s1.ToUpper() and s1.ToLower() create a copy of s1 in uppercase and lowercase, respectively.
• s1 + s2 has the same meaning as String.Concat(s1, s2). It constructs the concatenation of s1
and s2: a new string consisting of the characters of s1 followed by the characters of s2.
• s1 + v and v + s1 are evaluated by converting v to a string with v.ToString() and then con-
catenating the two strings. If v or v.ToString() is null, the result of the concatenation is s1.
• s1.Substring(i, n) creates a new string consisting of the n characters from s1 with indices
[i..(i+n-1)]. Throws ArgumentOutOfRangeException if i<0 or n<0 or i+n>s1.Length.
• s1.Split(cs) of type String[] is an array of the maximal (possibly empty) substrings of s1 that
contain no characters from cs, in order from left to right. Here cs is either a single argument of type
char[], or zero or more arguments of type char (example 23). Namely, cs is a so-called parameter
array (section 12.17.3).
• s1.StartsWith(s2) and s1.EndsWith(s2), both of type bool, determine whether s1 starts, re-
spectively ends, with the substring s2.
• s1.Remove(i, n) creates a new string from s1 by removing the n characters that have indices
[i..(i+n-1)]. Throws ArgumentOutOfRangeException if i<0 or n<0 or i+n>s1.Length.
• s1.Replace(s2, s3) creates a new string from s1 by replacing all non-overlapping occurrences
of the substring s2 with s3 from left to right. If each of s1 and s2 is a single character c1 and c2,
it is much faster to use s1.Replace(c1, c2) with signature Replace(char, char).
• s1.Trim(cs) creates a new string from s1 by removing all occurrences of characters in char[]
cs from the beginning and end of s1. To remove white space characters (including space, newline,
tabulator, form feed, and vertical tab) from the beginning and end of s1, use s1.Trim(). If string s1
contains only ASCII characters, this is equivalent to s1.Trim(" \n\r\t\f\v".ToCharArray()).
• The effect of s1.TrimStart(cs) and s1.TrimEnd(cs) is the same as that of s1.Trim(cs), except
that characters are only removed at the beginning or end, respectively, of s1.
• s1.ToCharArray() returns a new character array containing the characters of s1.
• More String methods are described in the .Net Framework class library (section 34).
Strings 21

Example 22 Determining Whether Strings Occur in Increasing Order

static bool Sorted(String[] a) {


for (int i=1; i<a.Length; i++)
if (a[i-1].CompareTo(a[i]) > 0)
return false;
return true;
}

Example 23 Calculating a Readability Index


The readability index of a text can be calculated using the following formula, where #sentences is the
number of sentences, #words the number of words, and #longwords the number of words longer than six
letters:
#words 100 × #longwords
Readability index = +
#sentences #words
Using the Split method, a text given as a String can be crudely split into sentences (separated by periods),
and the sentences can be further split into words (separated by commas or white space).

static double Readability(String text) {


int wordCount = 0, longWordsCount = 0;
String[] sentences = text.Split(new char[] {’.’}); // Split into sentences
foreach (String sentence in sentences) {
String[] words = sentence.Split(’ ’, ’,’); // Split into words
// String[] words = sentence.Split(new char[] {’ ’, ’,’}); // Equivalent alternative
wordCount += words.Length;
foreach (String word in words) {
if (word.Length > 6)
longWordsCount++;
else if (word.Length == 0)
wordCount--;
}
}
return (wordCount*1.0)/sentences.Length + (longWordsCount*100.0)/wordCount;
}

Example 24 Using a Class That Overrides the ToString Method


The class Point (example 43) declares a ToString method that returns a string of the point coordinates.
The operator (+) below implicitly calls the ToString method to convert the Point objects to strings.

Point p1 = new Point(10, 20), p2 = new Point(30, 40);


Console.WriteLine("p1 is " + p1); // Prints: p1 is (10, 20)
Console.WriteLine("p2 is " + p2); // Prints: p2 is (30, 40)
p2.Move(7, 7);
Console.WriteLine("p2 is " + p2); // Prints: p2 is (37, 47)
22 Strings

7.2 String Formatting


When producing a string to the console, to an output stream, to a string builder, or similar, the output
string may contain numeric values, dates, and other values that require special formatting such as right or
left justification, padding, and so on. The formatting can be specified using a format specification, which
is a sequence of characters of one of these four forms

{index,align:code} {index,align} {index:code} {index}

where index is a non-negative integer 0, 1, . . . specifying which value is to be formatted, and align is an
integer whose absolute value specifies the minimum number of characters in the resulting string. When
align is positive, the string to be formatted is right-justified (padded on the left) if shorter than the mini-
mum width, and when align is negative, the string to be formatted is left-justified (padded on the right) if
shorter than the minimum width. The code is a formatting pattern (sections 7.2.1 and 7.2.2).
Let fmt be a string that contains one or more format specifications, and let v0, v1, . . . , vn be values of
any type:

• String.Format(fmt, v0, v1, ...) of type String is fmt in which the format specifications
with index 0, 1, . . . are replaced by the formatted string representations of v0, v1, . . . , according to
the format specifications in fmt.

If the type of vi is DateTime or a numeric type (section 5.1), the format specification {i,align:code} is
replaced by the result of formatting vi using code, as shown in sections 7.2.1 and 7.2.2 and the associ-
ated examples. Otherwise the format specification is replaced with vi.ToString(). In both cases, the
resulting string is aligned as specified by align.
The String.Format method throws a FormatException if the index of a format specification is less
than 0 or greater than n, or if a formatting code in fmt is invalid.
The String.Format method is usually not called explicitly but it is called implicitly from
• Console.WriteLine(String fmt, Object v) and its overloads (example 26), and from other
similar output stream methods (section 25);
• AppendFormat(String fmt, Object v) and its overloads (section 8).
String formatting is culture-sensitive: The actual characters used for decimal points, thousand separator,
currency symbols, and so on, and the actual date formatting patterns, weekday names, month names, and
so on, depend on the NumberFormat and DateTimeFormat properties of the CurrentCulture property
of the current thread (example 30). The culture also affects the parsing of floating-point numbers. A
culture is represented by an object of class CultureInfo, and the culture of the current thread is either
determined externally by the operating environment or set explicitly in the source code. For instance, to
use the predefined U.S. English culture:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Strings 23

Example 25 String Formatting Using the String.Format Method


The result s below is | 3D326| 250662|3D326|250662|, where the symbol denotes a
blank. The format specifiers are explained in section 7.2.1.

int i = 250662;
String s = String.Format("|{0,10:X}|{1,10}|{2:X}|{3}|", i, i, i, i);

Example 26 String Formatting Using the Console.WriteLine Method


This example rolls a die one thousand times and counts frequencies. The frequencies are written to the
console (as in example 34), but string formatting is used instead of string concatenation.

Random rnd = new Random(); // Random number generator


int[] freq = new int[6]; // All initialized to 0
for (int i=0; i<1000; i++) {
int die = rnd.Next(1, 7); // Random integer in range 1..6
freq[die-1] += 1;
}
for (int c=1; c<=6; c++)
Console.WriteLine("{0} came up {1} times", c, freq[c-1]);

Example 27 String Alignment in Text Output


A 3 × 5 matrix represented by a two-dimensional array is filled with random numbers from 0 to 999. The
matrix is then printed with the numbers right-justified in each column.

Random rnd = new Random(); // Random number generator


int[,] m = new int[3,5]; // 3 x 5 matrix
for (int i=0; i<m.GetLength(0); i++)
for (int j=0; j<m.GetLength(1); j++)
m[i,j] = rnd.Next(1000); // Random integer in range 0..999

for (int i=0; i<m.GetLength(0); i++)


Console.WriteLine("{0,4} {1,4} {2,4} {3,4} {4,4}", m[i,0], m[i,1], m[i,2], m[i,3], m[i,4]);

The console output may look like this:


932 930 417 17 14
993 492 329 828 63
455 721 920 70 520
24 Strings

7.2.1 Number Formatting


The code part of a format specification for a value of numeric type may be a standard number formatting
code, which has the form c or cy or cyy, where c is a code character and y is a digit. The following standard
number formatting codes are predefined for integers (I) or floating-point numbers (F) or both (IF):

Code c String Format Precision Specifier y or yy Type


D or d Decimal number (possibly padded with zeros) Minimum number of digits I
X or x Hexadecimal (possibly padded with zeros) Minimum number of digits I
G or g General (default) Max. number of significant digits IF
N or n Number with thousand separators Number of fractional digits IF
F or f Fixed-point number Number of fractional digits IF
R or r Lossless value-string-value conversion (none) F
E or e Exponential notation Number of fractional digits IF
P or p Percent (value multiplied by 100 %) Number of fractional digits IF
C or c Currency amount Number of fractional digits IF

The code part of a format specification for a value of a numeric type may also be a custom number
formatting pattern, which is a combination of one or more of the following predefined custom number
formatting codes:

0 # . , % E0 e0 E+0 e+0 E-0 e-0 ; ’string’ "string"

See example 29 and the .Net Framework class library documentation for details.

7.2.2 DateTime Formatting


The code part of a format specification for an object of type DateTime may be one of the predefined
standard DateTime formatting codes:

Code Character Format


F or f Full date and time, with (F) or without (f) seconds
G or g General date and time, with (G) or without (g) seconds
s Sortable date and time in ISO 8601 format
u Universal sortable local date and time
U Universal sortable date and time: F converted to UTC
R and r RFC 1123 standard full date and time
D or d Full date, long (D) or short (d) format
Y and y Year and month
M and m Month and date
T or t Time, with (T) or without (t) seconds

The code part of a format specification for an object of type DateTime may also be a custom DateTime
formatting pattern, which is a combination of one or more of the many predefined custom DateTime
formatting codes. See the .Net Framework documentation for details.
Strings 25

Example 28 Some Standard Number Formatting Patterns and Their Effects


Formatting is culture-sensitive. This table shows the formatting obtained in the en-US culture.

Format Specifications
Number {0:D4} {0,7} {0:F0} {0:F2} {0,8:F3} {0:E4} {0,9:C}
0 0000 0 0 0.00 0.000 0.0000E+000 $0.00
1 0001 1 1 1.00 1.000 1.0000E+000 $1.00
145 0145 145 145 145.00 145.000 1.4500E+002 $145.00
-1 -0001 -1 -1 -1.00 -1.000 -1.0000E+000 ($1.00)
2.5 2.5 3 2.50 2.500 2.5000E+000 $2.50
-1.5 -1.5 -2 -1.50 -1.500 -1.5000E+000 ($1.50)
330.8 330.8 331 330.80 330.800 3.3080E+002 $330.80
1234.516 1234.516 1235 1234.52 1234.516 1.2345E+003 $1,234.52

Example 29 Custom Number Formatting

Format Specifications
Number {0:000.0} {0:###.#} {0:##0.0} {0:#0E+0} {0:00##;’(neg)’;’-’}
1230.1 1230.1 1230.1 1230.1 12E+2 1230
17 017.0 17 17.0 17E+0 0017
0.15 000.2 .2 0.2 15E-2 -
0 000.0 0.0 00E+0 -
-26 -026.0 -26 -26.0 -26E+0 (neg)

Example 30 Standard DateTime Formatting Codes and Their Effects


Here a DateTime value is shown in all standard formats using the en-US culture and the de-DE culture:

Format U.S. English German


F Monday, June 09, 2003 10:49:41 PM Montag, 9. Juni 2003 22:49:41
f Monday, June 09, 2003 10:49 PM Montag, 9. Juni 2003 22:49
G 6/9/2003 10:49:41 PM 09.06.2003 22:49:41
g 6/9/2003 10:49 PM 09.06.2003 22:49
s 2003-06-09T22:49:41 2003-06-09T22:49:41
u 2003-06-09 22:49:41Z 2003-06-09 22:49:41Z
U Monday, June 09, 2003 8:49:41 PM Montag, 9. Juni 2003 20:49:41
R Mon, 09 Jun 2003 22:49:41 GMT Mon, 09 Jun 2003 22:49:41 GMT
D Monday, June 09, 2003 Montag, 9. Juni 2003
d 6/9/2003 09.06.2003
Y June, 2003 Juni 2003
M June 09 09 Juni
T 10:49:41 PM 22:49:41
t 10:49 PM 22:49
26 String Builders

8 String Builders
A string builder, which is an object of class System.Text.StringBuilder, is an extensible and modifiable
string. Characters can be appended to a string builder without copying those characters already in the
string builder; the string builder is automatically and efficiently extended as needed.
By contrast, a String object s1, once created, cannot be modified. Using s1 + s2, one can append s1
and s2, but that creates a new string object by copying all the characters from s1 and s2; there is no way
to extend s1 itself by appending more characters to it. Thus to concatenate n strings each of length k by
repeated string concatenation (+), one must copy k + 2k + 3k + · · · + nk = kn(n + 1)/2 characters, and the
time required to do this is proportional to n2 , which grows rapidly as n grows.
Using a string builder, the concatenation of n strings each of length k requires only time proportional
to n, considerably faster than n2 for large n. To gradually build a string, use a string builder, especially for
repeated concatenation in a loop, as in examples 20 and 31. The expression s1 + · · · + sn is efficient; it
actually means new StringBuilder().Append(s1). . . . .Append(sn).ToString().
Let sb be a StringBuilder, s a String, and v an expression of any type:

• new StringBuilder() creates a new empty string builder.


• sb.Append(v) appends the string representation of the value v to the string builder, converting v
to a string by v.ToString(), see section 7. Extends sb as needed. Returns sb.
• sb.AppendFormat(String fmt, object v) appends the string String.Format(fmt, v) to the
string builder. Extends sb as needed. Returns sb. For possible formatting specifiers fmt, see
section 7.2.
• sb.Length of type int is the length of sb, that is, the number of characters currently in sb.
• sb[i] is character number i in the string builder, counting from zero. Thus sb[i] = c sets the
character at index i to c. Throws IndexOutOfRangeException (when getting a character) or Argu-
mentOutOfRangeException (when setting a character) if i<0 or i>=sb.Length.
• sb.Remove(i, n) deletes the characters with index i..(i+n-1) from the string builder, reducing
its length by n characters. Throws ArgumentOutOfRangeException if i<0 or n<0 or i+n>sb.Length.
Returns sb.
• sb.Insert(i, v) inserts the string representation of v obtained by v.ToString() into the string
builder, starting at position i, extending sb as needed. Returns sb. Throws ArgumentOutOfRange-
Exception if i<0 or i>sb.Length.
• sb.ToString() of type String is a new string containing the characters currently in sb.

Method Append is fast, but Remove and Insert may be slow when they need to move large parts of the
string builder’s contents, that is, when both i and i+n are much smaller than Length.
More StringBuilder methods are described in the .Net Framework class library (section 34).
String Builders 27

Example 31 Efficiently Concatenating All Command Line Arguments


When there are many (more than 50) command line arguments, this is much faster than example 20.
using System;
using System.Text; // StringBuilder

class StringBuilderConcatenate {
public static void Main(String[] args) {
StringBuilder res = new StringBuilder();
for (int i=0; i<args.Length; i++)
res.Append(args[i]);
Console.WriteLine(res.ToString());
}
}

Example 32 Replacing Occurrences of a Character by a String


To replace occurrences of character c1 with the string s2 in string s, it is best to use a string builder for the
result, since the size of the resulting string is not known in advance. This works well also when replacing
a character c1 with another character c2, but in that case the length of the result is known in advance (it
equals the length of s), and one can use a character array instead. Solving this problem by repeated string
concatenation (using res += s2 where res has type String) would be very slow.
static String ReplaceCharString(String s, char c1, String s2) {
StringBuilder res = new StringBuilder();
for (int i=0; i<s.Length; i++)
if (s[i] == c1)
res.Append(s2);
else
res.Append(s[i]);
return res.ToString();
}

Example 33 An Inefficient Way to Replace Occurrences of a Character by a String


The problem in example 32 can also be solved by destructively modifying a string builder with Remove
and Insert. However, repeated use of Remove and Insert is very inefficient: for a string of 200,000
random characters this method is approximately 100 times slower than that in example 32.
static void ReplaceCharString(StringBuilder sb, char c1, String s2) {
int i = 0; // Inefficient
while (i < sb.Length) { // Inefficient
if (sb[i] == c1) { // Inefficient
sb.Remove(i, 1); // Inefficient
sb.Insert(i, s2); // Inefficient
i += s2.Length; // Inefficient
} else // Inefficient
i += 1; // Inefficient
} } // Inefficient
28 Arrays

9 Arrays
An array is an indexed collection of zero or more variables, called elements. An array has a given element
type t, which can be any type. The value of an expression of an array type such as t[] is either null or a
reference to an array whose element type u is t or implicitly convertible to t. If t is a value type, u must
equal t. Assignment of an array to a variable assigns only the reference; it does not copy the array, as
illustrated by arr1 and arr2 in example 71.
The rank of an array is the number of index expressions required to access an element. Although
an array of rank n is sometimes called an n-dimensional array, note that a Java-style “multidimensional”
array of type t[]...[] is actually an array of rank 1 whose elements happen to be arrays (section 9.2.2).

9.1 One-Dimensional Arrays


In an array with rank 1 and length  ≥ 0, the elements are indexed by the integers 0, 1, . . . ,  − 1. A new
array of length  with element type t is created (allocated) using an array creation expression, which can
take two forms. The first form of array creation expression is
new t[]

where  is an expression of type int. This creates a new array with rank 1, also called a one-dimensional
array, with  elements, all initialized with the default value for type t (section 6.2). The size argument 
may be zero, but if it is negative then OverflowException is thrown.
The second form of array creation expression explicitly lists the elements of the new array:
new t[] { expression, ..., expression }

The type of each expression must be implicitly convertible to t. This array creation expression is evaluated
by creating a new array of rank 1 whose length equals the number of expressions. Then the expressions
are evaluated from left to right, and their values are converted to type t and stored in the array.
A local variable or field of array type may be initialized at declaration, by assigning null or an array
to it. When an array creation expression is used to initialize an array variable at its declaration, new t[]
may be left out, so these two declarations are equivalent:
t[] a = new t[] { expression, ..., expression };
t[] a = { expression, ..., expression };
Note that the declared variable a cannot occur in expression: it has not yet been initialized when the
expressions are being evaluated. Also note that there are no array constants: a new distinct array is
created every time an array creation expression is evaluated.
Let a be an array expression of type t[] whose value is an array of length  with element type u. Then
the array access expression a[i] denotes element number i of a, counting from 0; this expression has
type t. The integer expression i is called the array index. If the value of i is less than 0 or greater than or
equal to , then an IndexOutOfRangeException is thrown.
When the element type u is a reference type, then every array element assignment a[i] = e checks
that the value of e is null or is implicitly convertible to the element type u. If this is not the case, then
an ArrayTypeMismatchException is thrown. This check is made before every array element assignment
at run-time, but only for reference types. For value types, the type check is performed at compile-time.
Arrays 29

Example 34 Creating and Using One-Dimensional Arrays


This example rolls a die one thousand times, then prints the frequencies of the outcomes.

Random rnd = new Random(); // Random number generator


int[] freq = new int[6]; // All elements initialized to 0
for (int i=0; i<1000; i++) {
int die = rnd.Next(1, 7); // Roll die
freq[die-1] += 1; // Increment frequency
}
for (int c=1; c<=6; c++) Console.WriteLine(c + " came up " + freq[c-1] + " times");

Example 35 Using an Initialized Array


Method CheckDate below checks whether a given date is legal in a non-leap year. The array should be
created once, outside the method; otherwise a distinct new array is created for every call to the method.

static readonly int[] days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static bool CheckDate(int mth, int day)
{ return (mth >= 1) && (mth <= 12) && (day >= 1) && (day <= days[mth-1]); }

Example 36 Array Element Assignment Type Check at Run-Time


This program compiles all right, but at run-time a[2]=p1 throws ArrayTypeMismatchException, since
the class Point of the object bound to p1 is not implicitly convertible to a’s element type RedPoint.

Point[] a = new RedPoint[10]; // Length 10, element type RedPoint


Point p1 = new Point(42, 117); // Compile-time type Point, class Point
RedPoint cp = new RedPoint(3,4); // Compile-time type RedPoint, class RedPoint
Point p2 = cp; // Compile-time type Point, class RedPoint
a[0] = cp; // OK, RedPoint is subclass of RedPoint
a[1] = p2; // OK, RedPoint is subclass of RedPoint
a[2] = p1; // Run-time error: Point not subclass of RedPoint

Example 37 Array Assignment Compatibility


In an assignment a = e where a and e have array type, e must be implicitly convertible to a as defined
in section 5.3.2. In this example, the assignment to a1 is legal because String and Object are reference
types and String is implicitly convertible to Object. The assignment to a2 is obviously legal as the arrays
have the same element type, and the array creation expression is legal because the integers 1 and 2 are
implicitly convertible to Object by a boxing conversion. The assignments to a3 and a4 are illegal because
int is not a reference type and so int[] is not implicitly convertible to Object[] or double[].

Object[] a1 = new String[] { "a", "bc" }; // Legal: array conversion


Object[] a2 = new Object[] { 1, 2 }; // Legal: conversion of 1, 2
// Object[] a3 = new int[] { 1, 2 }; // Illegal: no array conversion
// double[] a4 = new int[] { 1, 2 }; // Illegal: no array conversion
30 Arrays

9.2 Multidimensional Arrays


There are two ways to form multidimensional arrays: rectangular arrays and jagged arrays. Here are a
rectangular 3 by 2 array and a “two-dimensional” jagged array; example 38 shows how to create them:
0.0 0.1 0.0
1.0 1.1 1.0 1.1
2.0 2.1 2.0 2.1 2.2

9.2.1 Rectangular Arrays


Rectangular (C-style) arrays have types of form t[], t[,], t[,,], and so on, where t is not an array type.
The array type t[,...,], with n − 1 commas, has rank n and is also called an n-dimensional array type.
When n = 1, this is just a one-dimensional array type t[], as in section 9.1. A variable of type t[,...,]
is either null or holds a reference to an n-dimensional array; assignment of an array does not copy it.
A rectangular n-dimensional array may be created in one operation by an array creation expression:
new t[1 ,...,n ]

where 1 , . . . , n are expressions of type int, as for one-dimensional arrays. This creates an array with
1 · 2 · · · · · n elements, all initialized with the default value for type t (section 6.2). Alternatively, an array
creation expression for a rectangular n-dimensional array may have this form:
new t[,...,] { ... { expression,...,expression }, { expression,...,expression }, ... }

where there are n − 1 commas in t[,...,] and the nesting depth of curly braces is n. The expressions
are evaluated from left to right and implicitly converted to type t, as for one-dimensional arrays.
To access an element of an n-dimensional rectangular array a, use n index expressions: a[i1 ,...,in ].

9.2.2 Arrays of Arrays (Jagged Arrays)


In general, an array type has form t[K1 ][K2 ]...[Kh ], where each Ki is a list of ki − 1 commas, ki ≥ 1,
and t is not an array type. This type describes k1 -dimensional rectangular arrays of k2 -dimensional
rectangular arrays of . . . kh -dimensional arrays of element type t. For instance, double[,][] is the
type of two-dimensional arrays of one-dimensional arrays of double.
A common special case is Java-style “h-dimensional” array types t[]...[] where k1 = · · · = kh = 1.
Thus a “two-dimensional” array of type t[][] is a one-dimensional array whose elements are arrays of
type t[]. The element arrays may have different lengths, so the array may be non-rectangular or jagged.
A jagged (Java-style) “h-dimensional” array t[][]...[], with h empty square brackets [], must be
created one dimension at a time:
new t[1 ][]...[]

This creates a one-dimensional array with 1 elements, all initialized to null, and all of type t[]...[],
where there are h − 1 empty square brackets []. One may subsequently create arrays of type t[]...[]
and assign them to the elements of the one-dimensional array.
To access an element of an h-dimensional jagged array a, use h index expressions: a[i1 ][i2 ]...[in ].
Element access in a jagged array is likely to be less efficient than in a rectangular array.
Arrays 31

Example 38 Creating Multidimensional Arrays


This example shows two ways (r1, r2) to create the rectangular array and three ways (t1, t2, t3) to create
the jagged array shown in section 9.2. One cannot create a jagged array in one operation (as in t4).
double[,] r1 = { { 0.0, 0.1 }, { 1.0, 1.1 }, { 2.0, 2.1 } };
double[,] r2 = new double[3,2];
for (int i=0; i<3; i++)
for (int j=0; j<2; j++)
r2[i,j] = i + 0.1 * j;

double[] row0 = { 0.0 }, row1 = { 1.0, 1.1 }, row2 = { 2.0, 2.1, 2.2 };
double[][] t1 = { row0, row1, row2 };
double[][] t2 = { new double[] {0.0},
new double[] {1.0, 1.1},
new double[] {2.0, 2.1, 2.2}};
double[][] t3 = new double[3][]; // Creates first-dimension array
for (int i=0; i<3; i++) {
t3[i] = new double[i+1]; // Creates second-dimension arrays
for (int j=0; j<=i; j++)
t3[i][j] = i + 0.1 * j;
}
// double[][] t4 = new double[3][3]; // Illegal array creation

Example 39 Using Multidimensional Arrays


To store the exchange rate between U.S. dollars and euros ($US per euro) for every day in the years 2000–
2009 use an array rate of type double[,][]: a two-dimensional rectangular array of one-dimensional
arrays with element type double. The idea is that rate[y,m][d] holds the exchange rate for year
y + 2000, month m + 1, day d + 1. An array of type double[,][] is used because each of the 10 years
has 12 months (hence rectangular), but not all months have the same number of days (hence jagged).
double[,][] rate = new double[10,12][];
rate[0, 0] = new double[31]; // Jan 2000 has 31 days
rate[0, 1] = new double[29]; // Feb 2000 has 29 days
rate[0, 2] = new double[31]; // Mar 2000 has 31 days
rate[0, 3] = new double[30]; // Apr 2000 has 30 days
rate[1, 1] = new double[28]; // Feb 2001 has 28 days
...
rate[0, 1][27] = 0.9748; // 28 Feb 2000
rate[0, 1][28] = 0.9723; // 29 Feb 2000
rate[0, 2][ 0] = 0.9651; // 1 Mar 2000
...
for (int y=0; y<rate.GetLength(0); y++)
for (int m=0; m<rate.GetLength(1); m++)
if (rate[y,m] != null)
for (int d=0; d<rate[y,m].Length; d++)
if (rate[y,m][d] != 0.0)
Console.WriteLine("{0:D4}-{1:D2}-{2:D2}: {3:F4} $US/euro",
y+2000, m+1, d+1, rate[y,m][d]);
32 Arrays

9.3 Class Array


All array types are derived from class Array, and the members of an array type are those inherited from
class Array. Let a be a reference of array type, o an object of any type, and i, i1, . . . , in integers:

• a.Length of type int is the length of a, that is, the total number of elements in a, if a is a one-
dimensional or a rectangular multidimensional array, or the number of elements in the first dimen-
sion of a, if a is a jagged array.
• a.Rank of type int is the rank of a (sections 9 and 9.2.2).
• a.GetEnumerator() of type IEnumerator is a non-generic enumerator (section 27.2) for iterating
through a. This enables the foreach statement to iterate over an array (section 13.6.2 and exam-
ple 40). If a is a one-dimensional array of type t[], one can get a type-safe generic enumerator of
type IEnumerator<t> by computing ((IList<t>)a).GetEnumerator().
• a.GetLength(i) of type int is the number of elements in dimension i (examples 27 and 39).
• a.SetValue(o, i1,..,in) of type void performs the same assignment as a[i1,...,in] = o
when a has rank n; and a.GetValue(i1,...,in) of type Object is the same as a[i1,...,in].
More precisely, if a[i1,...,in] has reference type, then GetValue returns the same reference;
otherwise it returns a boxed copy of the value of a[i1,...,in].
• a.Equals(o) of type bool returns true if a and o refer to the same array object, otherwise false.

Class Array provides static utility methods, some of which are listed below. These methods can be used on
the ordinary array types t[] which derive from class Array. The methods throw ArgumentNullException
if the given array a is null, and throw RankException if a is not one-dimensional.

• static int BinarySearch(Array a, Object k) searches the one-dimensional array a for k


using binary search. Returns an index i>=0 for which a[i].CompareTo(k) == 0, if any; other-
wise returns i<0 such that ~i would be the proper position for k. The array a must be sorted, as by
Sort(a), or else the result is undefined; and its elements must implement IComparable.
• static int BinarySearch(Array a, Object k, IComparer cmp) works similarly, but com-
pares array elements using the cmp.Compare method (section 27.3). The array must be sorted, as
by Sort(a, cmp), or else the result is undefined.
• static void Reverse(Array a) reverses the contents of one-dimensional array a.
• static void Reverse(Array a, int i, int n) reverses the contents of a[i..(i+n-1)].
• static void Sort(Array a) sorts the one-dimensional array a using quicksort, comparing ar-
ray elements using their CompareTo method (section 27.3). The array elements must implement
IComparable. The sort is not stable: elements that are equal may be swapped.
• static void Sort(Array a, IComparer cmp) works similarly, but compares array elements
using the cmp.Compare method (section 27.3).
• static void Sort(Array a, int i, int n) works similarly but sorts a[i..(i+n-1)].
• static void Sort(Array a, int i, int n, IComparer cmp) sorts a[i..(i+n-1)] using
cmp.Compare.
Exploring the Variety of Random
Documents with Different Content
average size

Color: Iridescent steel blue with deep red fins. Sex determined same
as Silver Tetra.

Breeding Habits: Egg layers. Use large tank, cover bottom with fine
plants, and ample tall ones. Fish spawn at surface, some eggs
adhering to tall plants, others falling. Remove parents. Fry appear
in about 24 hours. Feed Brine Shrimp. Fry grow rapidly.

Temperature: 70° to 78° F.

Temperament: Peaceful.

SILVER TETRA: CTENOBRYCON


SPILURUS
(Br. Guiana)
Color: Steel blue body covered with very fine bright silver scales. Body
very thin. Large black spot at base of caudal. Tetras are all easily
identified by the small adipose fin between dorsal and caudal. Male
slightly smaller with invisible processes on anterior tip of anal
which catch in fine net. Sex is determined in this way.

Breeding Habits: Egg layers—lay great quantities of adhesive eggs


on fine plants. Plants or parents should be removed as soon as
spawning is completed. Fry will make their appearance in a few
days. Be sure there are no snails in tank with eggs.

Temperature: 70° to 90° F.

Maturity: 6 to 8 months.

Temperament: Very active. Not for community tank.

16

TETRA FROM RIO (above): HYPHESSOBRYCON


FLAMMEUS
(Brazil)
TETRA FROM BUENOS AIRES: HEMIGRAMMUS
CAUDOVITTATUS
(Argentina)
average size

Color: TETRA FROM RIO—body bright silver—3 black bars near head;
fins brilliant red edged with black; black edge on anal of male
wider than on female. During mating season red runs well into
body. TETRA FROM BUENOS AIRES—body bright silver, fins blood
red. Large diamond shaped spot at base of caudal. Sex determined
same as Silver Tetra.

Breeding Habits: Egg layers. Use 15 gallon tank, 6 to 8 inches of


water. Stock tank heavily with Cabomba, Myriophyllum, or other
fine floating plants, also a thicket on bottom. Semi-adhesive eggs
are deposited on plants, some sinking to bottom. Best results are
obtained with 2 males and 1 female. Remove parents after
spawning is completed. Fry appear in about 3 days. Tiny fry hang
on plants and sides of aquarium about 3 days. Tetras may not
spawn immediately—have patience.

Temperature: 70° to 90° F.

Maturity: From Rio—8 months. Buenos Aires—10 months.


Temperament: From Rio—Very peaceful, Buenos Aires—Fairly
peaceful.

17

PRISTELLA RIDDLEI: (above)


(Venezuela and Guiana)

average size

Color: Silvery body, caudal reddish, anal and dorsal light yellow with
dark spot. Difficult to distinguish sex.

Breeding Habits: Egg Layers. Spawn on fine plants, Myriophyllum or


Cabomba—very small adhesive eggs, expelled 6 or 8 at a time,
often fall to bottom. Sometimes as many as 200 eggs at a
spawning. Remove parents after spawning.

Temperature: 72° to 80° F.; best above 75° F.

Maturity: About 1 year.


Temperament: Peaceful.

HEAD AND TAIL LIGHT: HEMIGRAMMUS


OCELLIFER
(Amazon River, S. A.)
Color: Body translucent green, faint gold line through center of body,
thin black line toward caudal base broadens into diamond shape.
Gleaming gold spot on tail and brilliant red eye give fish its
common name. Male smaller, more slender and has pointed
instead of rounded dorsal.

Breeding Habits: Egg layers. Adhesive eggs are deposited on fine


plants. Use 2 males to one female for best results. Fry hatch in 2
days. (See Pristella Riddlei.)

Temperature: 72° to 80° F.

Maturity: About 8 months.

Temperament: Peaceful. Young fairly hardy.

FEATHERFIN: HEMIGRAMMUS
UNILINEATUS
Color: Like above Pristella Riddlei but has a black and white line down
the anal fin.

Breeding Habits and Temperament: like Pristella.

18
JEWEL FISH: HEMICHROMIS
BIMACULATUS
(Africa)

average size

Color: Body bright scarlet blending to rich olive on back. Emerald dots
(jewels) in irregular lines cover body and vertical fins. Frequently
difficult to obtain mated pair.

Breeding Habits: Egg layers—eggs are deposited on smooth stone or


flower pot, to which they adhere. During incubation (about 30
hours) one parent stands guard, constantly fanning to circulate
water over eggs. Fry are unable to swim first three days so parents
make hollow in sand where fry are placed and guarded. After fry
can swim, they form school with parents in center. Remove parents
when fry are about one-fourth grown or sooner. Parents must not
be excited or they will eat spawn or fry.

Temperature: 70° to 90° F. Fry above 75° F. Breed best at 80° F.


Maturity: 10 to 14 months.

Temperament: Very savage—male frequently attacks carefully mated


female.

* * * * * * * *

To spawn Cichlids (Jewel, Angel, Orange Chromide, Blue Acara and


Mouthbreeder) purchase several young fish—bring them to maturity
together. When ready for breeding a mated pair will be found
associating together and separated from the others.

Avoid disturbing Cichlids, any disturbance or noise may cause them to


devour their eggs or young.

19

ANGEL FISH: PTEROPHYLLUM SCALARE


(Amazon River, S. A.)

Reduced
Color: Bright silver, black bars, body very thin. Black bars disappear
when disturbed or frightened. Difficult to distinguish sex.

Breeding Habits: Egg layers—very difficult to breed. Prefer sides of


aquarium or Sagittaria Gigantea for depositing eggs. Eggs are
fanned constantly by parents. Fry appear in about 8 days;
guarded, and transferred from one plant to another or depression
in sand, by parents. Fry swim in about a week and resemble
thread like worms. Remove parents when fry begin to swim. Feed
infusoria. Fry take shape of scalare in 3 to 5 weeks.

Temperature: 70° to 90° F. 85° for spawning.

Maturity: One to one and a half years. Growth depends upon quality
and quantity of food and size of tank. Angel fish should have as
much live food as possible, largest tank available.

Temperament: Peaceful. Easily frightened. Keep in large well planted


aquarium otherwise they may dart against sides and kill
themselves. Should be fed live food frequently. Large specimens
are not recommended for community tank.

20

BLUE ACARA: AEQUIDENS LATIFRONS


(Central America)
one half size

Color: Yellowish brown with several dark vertical bands. One of these
bands widens in center of the body into a spot. Lines of shining
blue dots cover the entire body. Dorsal, anal and caudal are wine
red with rows of blue and blue-green spots. Both sexes similar,
female slightly subdued in color.

Breeding Habits: Egg layers—Mate fish of approximately the same


size. Provide a clean flower pot for the fish to deposit their spawn.
The adhesive eggs are placed on the inside of the flower pot and
are then fertilized by the male. Eggs are fanned by the parents and
fry appear in 3 or 4 days. Parents prepare a depression in the sand
and taking the newly hatched fry in their mouths deposit them into
these holes where they are carefully guarded by the parents.
Young live in a swarm in this “nest” for several days. Then they
swim freely and must be fed infusoria. Parents may be removed
soon after fry swim freely. The Blue Acara is hardy, prolific, easily
spawned, and the fry are hardy and develop rapidly.

Temperature: 70° to 85° F.


Maturity: Breed in about 8 months.

Temperament: Not peaceful—except with very large fish.

21

MOUTH BREEDER: HAPLOCHROMIS


STRIGIGENA
(Egypt)

one half size

Color: Body light blue gray—fins yellowish—head very massive.

Breeding Habits: Egg layers—deposit spawn in depression in sand.


After spawning is completed female picks up eggs and carries
them in her mouth. Water is circulated over eggs by a chewing
movement. Female refuses food during period she carries eggs.
Male should be removed as soon as female picks up eggs as he
may bother her. Fry appear in about two weeks, but at the
slightest sign of danger rush back into the mother’s mouth. This
continues until fry are too large for the maternal jaw. Female
should be removed when fry are about 5 weeks old. Because of
“fast” while carrying eggs, should be bred but 2 or 3 times a year.

Temperature: 70° to 85° F.

Maturity: 12 to 14 months.

Temperament: Rather vicious.

ORANGE CHROMIDE: (below) ETROPLUS


MACULATUS
(India)
Color: Golden orange, 3 blue-black dots on sides crossed by rows of
small reddish dots. Dorsal brown, anal and pectorals dark. Sex
difficult to distinguish.

Breeding Habits: Egg layers—Spawn on flower pot or stones placed


in the aquarium. Fry hatch in about 4 days and are moved into pits
in sand. Fry swim freely in about 6 days. Remove parents in about
two weeks.

Temperature: 70° to 80° F.

Maturity: about 6 to 8 months.

Temperament: Usually peaceful in large well planted tank.

22

THREE-SPOT GOURAMI: TRICHOGASTER


TRICHOPTERUS
(India)
average size

Color: Silvery olive with black spot in center of body, another at caudal
base—the eye making the third spot.

Breeding Habits: Same as Dwarf Gourami.

Temperature: 70° to 85° F.

Maturity: 10 months.

Temperament: Not recommended for community tank.

BLUE GOURAMI: TRICHOGASTER


SUMATRANUS
Form and size like three-spot gourami but color light blue.
DWARF GOURAMI: (below) COLISA
LALIA (India)
Color: Body light blue crossed by orange-red stripes. Large fins colored
same as body. Female—subdued in color and fins (dorsal and anal)
slightly rounded.

Breeding Habits: Bubble nest builders—male blows nest of bubbles


on surface of water among floating plants. Female frequently
assists, weaving bits of plants into nest. Female is coaxed beneath
nest where eggs are expelled and fertilized. Male catches eggs and
blows them into bubble nest. Remove female. Eggs hatch in
several days. Male guards nest, blowing fry back into nest until
they are able to swim freely, to prevent their drowning. Remove
male when fry are 4 days old.

Temperature: 70° to 90° F.

Maturity: 8 to 10 months.

Temperament: Exceedingly peaceful and friendly.

Labyrinth fish prefer shallow water—spawning tank not to exceed 6″—


tank for fry not to exceed 4″.

23

PARADISE: MACROPODUS
OPERCULARIS
(South China)
average size

Color: Body dark with vertical bars of deep red against bluish green
background. Fins similar in color, caudal deep red. Female—shorter
fins, color very pale during mating.

Breeding Habits: Bubble nest builder. When pair have mated


(frequently after the death of several undesirable females) the
male builds a floating nest of bubbles. Male coaxes female under
nest, winds himself about her, a gentle pressure expelling eggs. He
then gathers eggs in his mouth and blows them into nest. Falling
eggs and young fry are carefully blown back into nest by male.
Remove female when spawning is over. Fry appear within 36
hours. Remove male in about 4 days.

Temperature: 50° to 90° F.

Maturity: About 12 months.

Temperament: Vicious, keep pair separated except when spawning.


(see Bettas.)
Labyrinth Fish (Gourami, Paradise, Bettas) are air breathers, coming to
the surface every few minutes for a bubble of air. For this reason they
can stand crowding, providing water is kept clear. Fry do not develop
this characteristic for several weeks so must be provided with a large
shallow container with ample oxygen.

24

BETTAS: SIAMESE FIGHTING FISH


(Siam)

average size

Color: This attractive group (all hybrids of BETTA SPLENDENS) have


many color variations, all exceptionally attractive. BETTA
CAMBODIA: gold colored body—bright red fins. Those with most
red in body known as BETTA RUBRA. BETTA CYANA—body and fins
iridescent cornflower blue. Others often have various shades of
blue, green, red and purple predominating. Females—subdued in
color and lack long flowing fins.
Breeding Habits: Bubble nest builders—Male builds floating nest of
bubbles 3 to 6 inches in diameter. Female is coaxed and forced
under nest, male embraces her expelling eggs. Male catches eggs
and blows them into bubble nest. Remove female. Fry hatch in 48
hours. Remove male in 10 days. Do not crowd fry.

Temperature: 65° to 90° F. 80° F. best for spawning.

Maturity: 8 to 10 months.

Temperament: Savage—two males will fight to a finish. Siamese


wager on outcome of these battles. Not advisable to keep mated
pairs together except when spawning. Separate pairs with glass
placed diagonally across aquarium. When spawning, if male
attacks female too viciously, replace glass.

(One of these fish may be kept in Community Tank—they seem to


attack only their own species.)

25

PANCHAX FROM MADRAS: PANCHAX


PARVUS
(India)
average size

Color: Male, rich deep greenish olive, sides covered with rows of
gleaming red and green spots, anal bright orange and red. Dorsal
and caudal are of similar colors. Female—dull with light orange
fins.

Breeding Habits: Egg layers, spawn readily in small tank, riccia being
a favorite plant for this purpose.

Temperature: 72° to 80° F.

Temperament: peaceful.

RASBORA HETEROMORPHA: (below)


(Sumatra)
Color: Silvery copper with large blue-black triangle from dorsal to
caudal base. Dorsal and caudal red. Scales above black triangle
wider on male.
Breeding Habits: Egg layers—Difficult to breed. Female swims upside
down against leaf of Cryptocoryne, expelling eggs, most of which
drop to bottom. Remove parents after spawning. Fry hatch in
about 2 days and resemble zebra fry. Swim freely in about 5 days.
Use 3 males and 2 females. Do not have aquarium in direct rays of
sun.

Temperature: 72° to 85° F.

Maturity: Breed at 10 months.

Temperament: Peaceful.

26

CATFISH: CORYDORAS PALEATUS


(South America)

Color: Shining olive green, towards the anal: yellowish to white. Body
covered with dark spots changing according to the surroundings.
Average size: 1 to 2 inches.
Breeding Habits: Egg layer. Distinguishing sex marks: male smaller
than female, and has pointed ventral fins, which are in the female,
rounded. Best breeding results are obtained in a large aquarium.
Two to three males for one female. Temperature 75 to 80 degrees.
60 to 500 eggs are carried by female in her ventral fins to a clean
spot which can be the glass of the aquarium, a plant or stone.
Babies hatch after 6 to 9 days. The opinion of breeders is divided
as to whether parents should be removed. Good results were
obtained either way.

Temperament: Paleatus Catfish are the most peaceful fish and very
essential for the maintenance of every balanced aquarium. They
are regarded as the officers of the “Dept. of Sanitation” among
successful aquarists. Paleatus is a ground fish, tirelessly picking up
food remnants and left-overs which other fish do not eat. Through
this activity, Paleatus helps to keep the food particles from
contaminating the water. Catfish dart up to the surface to breathe
atmospheric air.

27

WHITE CLOUD MOUNTAIN FISH:


TANICHTHYS ALBONUBES
(China)
Color: Form and color similar to Pearl Danio but with gold and blue line
from eye to caudal fin, dorsal and caudal fins deep red, male has
white tip above red caudal fins.

Breeding Habits: Average temperature 80 degrees. Eggs not


adhesive. One female to two males, eggs hatch after two to three
days. Remove parents after spawning. Tiny fry must be supplied
with infusoria or better still, Brine Shrimp (see p. 27).

Temperament: Peaceful and hearty, “called poorman’s Neon Tetra”


since the bright colored babies closely resemble Neon Tetras.
WHITE PARADISE: ALBINO PARADISE
Color: Generally white and the red bars show faintly. Like most albinos
their eyes are pink.

Breeding Habits: Just like their original form, the Red Paradise. The
albino color breeds true. (See page 23.)

BLACK TETRA: GYMNOCORYMBUS


TERNETZI
(Paraguay)
Color: Same size like Tetra from Rio but black in color.

Breeding Habits and Temperament also like Tetra from Rio. (see
page 16.)

BLUE MOLLY: MOLLIENISIA SPHENOPS


Color: Sphenops are found in various color schemes varying from jet
black to pure light blue, very often blue body with scattered black
spots. The caudal of male adorned with bright orange border.

Breeding Habits: Heartier and more easily bred than ordinary Black
Mollies.

LIBERTY MOLLY: VAR. SPHENOPS


Color: Body color of male and female light blue, but males dorsal
shows “red, white and blue”.
Breeding Habits: (see page 11.)

28

GOLD FISH:

Veiltail

History: The Gold Fish, the oldest and most popular of our numerous
Aquarium Fish, was developed by the Chinese during the Sung
Dynasty (960-1278) from the wild Carassius Auratus to the various
varieties now familiar to us.

In the year 1750 Madame de Pompadour imported the first Goldfish


into France as showpieces for the ornamental waterpools in her vast
gardens. In 1856, P. T. Barnum was sent by The American Museum to
search for oddities in Europe and to study the then popular fad of
keeping live fish in aquariums. Thus our now familiar Goldfish made its
debut in America. With its golden beauty and its sturdiness, the
Goldfish quickly became the Parlor Pet of our parents and
grandparents. Today the sales of American-bred Goldfish run into the
millions.

It would be beyond the limits of this booklet to explain and fully 29


describe all the various forms and color variations of our goldfish,
as there are Comets, Fantails, Shubunkins, Black Moors, etc. Most
Goldfish do not reach their full life span of 4 to 6 years and often more,
because they are fed too much and are given too little “Living Space.”
Feed your fish only once a day during the morning and make sure that
all food is consumed within 10 to 15 minutes. Any surplus food will fall
to the bottom and will contaminate the water. The surest sign of
overfeeding is cloudy and milky looking water. This bad water is poor in
oxygen and the fish will hang on the surface and frantically gasp for
atmospheric air. Any nationally known brand of Goldfish food will be
suitable for your fish, but once more: DO NOT OVERFEED. The proper
size of the aquarium should be comparable to the amount of fish or
vice versa. The happy medium is about 1 small fish per gallon of water.
An aquarium of five gallons capacity can, therefore, hold no more than
4 to 5 small Goldfish, but fish of larger size must have much larger
space. The most suitable temperature is between 60 and 70 degrees,
Fahrenheit.

Breeding Hints: During the breeding season which falls during the
first seven months of the year, the male will show small warts of
pin point size on his gill plates. The female is shorter than the male
but fuller in body, more so, when carrying spawn. A mature fish is
about 3-10 inches long, depending on type and a pair must
therefore have a breeding aquarium of at least 10 gallons. The fish
will spawn on myriophyllum, long rooted water hyacinths, or other
soft bunchy plants and the eggs will hatch in about 4-7 days. Since
the parent fish like to eat their own spawn, it is therefore advisable
to remove either the parents or the plants with their adhering
eggs. The newly hatched babies are fed with infusoria and later on
with fish food of a fine grain.

Diseases: Fin Congestion and Fungus are the most frequent Goldfish
diseases. Their best cure is the salt treatment which is described
on page 33.

30

TURTLES

Baby turtles are very easily kept as pets and require little care. While in
captivity, Turtles will forget their time schedule and will not hibernate.
Any round or oval bowl, an aquarium or a flat pan with a rim
sufficiently high to prevent the turtle from crawling out, is an adequate
home. In this container, place white or colored pebbles, and in the
center a flat stone. Fill the container with clean water of room
temperature (60 to 80 degrees, fahrenheit) but see to it that the stone
is not covered by the water for it will serve as an “Island” and thus give
the turtle a chance to leave the wet element when desired. The best
place for the bowl is in a light place, but special care should be taken to
see that the bowl is not exposed too long to the direct sun. Ant Eggs,
commonly packed as “Turtle Food” will mainly be their diet but lean raw
beef, which is finely scraped, will be an appreciated change. The same
applies for green lettuce, rainworms, etc. A variation in food and
sunshine will prevent blindness, but should a turtle get a white film
over its eyes, a few drops of Cod liver Oil forced by a medicine dropper
in its mouth, might help. Boric acid swabbed over the eyes will also be
beneficial. Turtles will not feed “on land” therefore all food should be
placed in the water. Water should be changed two to three times
weekly.

31
HEALTH
It is much easier to keep fish healthy than to cure them.

Disturb your fish as little as possible.

Fish in good health are active and keep dorsal fin erect. (Folded fins for
a short period do not mean a sick fish.)

Most fish ills develop from chills. Keep fish above lowest safe
temperature. Young fry especially should be kept warm.

Avoid extremes of temperature. Avoid sudden changes of temperature.


Provide some type of aquarium heater for cold months.

Do not crowd fish—be sure plants are thriving and there is ample
oxygen in water.

Fish constantly at top indicate foul water and lack of oxygen. Remove
part of water and replace with fresh of same temperature.

Dying plants cause much trouble—be sure plants are healthy and
growing.

It is much easier to keep fish healthy in a large tank (above 5 gallons).


A large tank maintains a more uniform temperature, allows more air
surface, plants thrive better, and water is not fouled so easily by excess
food.

An aquarium can be maintained in healthy condition, both plants and


fish thriving, under artificial lighting furnished by an ordinary light bulb.

Vary the diet for the fish. Feed only as much as they will eat in ten
minutes. Feed sparingly and several times a day if necessary. Use glass
feeding ring. (Fig. 4). All uneaten food drops to one spot where it can
be easily removed with a dip tube.

Health and growth of fry depend upon oxygen supply. Use tank with
large air surface. BE SURE AND DO NOT CROWD YOUNG FRY.
Crowding stunts growth and frequently causes disease, and loss of
whole brood. Fry demand approximately same amount of water as
adults—see page 31.

FIG·4

Tropicals in poor condition, (usually indicated by folded fins).


Fish constantly at top indicate foul water and lack of oxygen.
SEVERAL HOURS DIRECT SUNLIGHT DAILY
Always keep glass cover on aquarium.
Always keep a thermometer in aquarium.

Never give fish more food than they can clean up in ten minutes.
32
FOOD
Do Not Overfeed—Never give fish more food than they can clean up
in ten minutes.

Vary the Diet—Have several kinds of food on hand at all times. Dried
Shrimp, Dried Daphnae, scrapings from raw beef, bits of canned
salmon, bits of boiled spinach, finely crumbed graham cracker, bits of
yolk of boiled egg, and most of the prepared foods are excellent but
should be supplemented with some form of live food. Once a week
they should be fed chopped earth worms or Enchytrae (White worms).
Feed live bearer’s fry small quantity of fine foods several times a day.
Feed egg layer’s fry Brine Shrimp twice a day the first couple weeks
and then feed same as live bearer’s fry.

Several Feedings a Day—Feeding a very small quantity of food


several times a day (what the fish will clean up in several minutes) is
probably more desirable than one feeding providing great care is taken
not to feed too much at one time.

Tropicals Will Not Overeat—Unlike goldfish, tropicals will eat only as


much as they need but great care must be exercised in order to allow
no uneaten food in the aquarium to foul the water and cause disease.

Tubifex worms are found in fresh water streams and rivers, close to
shore in soft loamy bottom. They are an excellent live food provided
they are fed to the fish with care. Keep in cool place in container
having large air surface with just enough water to cover them. Since
they bury themselves in the gravel, it is best to feed them to the fish
with a worm feeder. The best type of feeder has a quantity of small
holes through which the worms wriggle into the mouths of the fish
eagerly waiting below. For baby fish it is best to cut the worms into
small pieces.
Enchytrae (White Worms) multiply rapidly in a wooden box (about
10″ square) filled with about 5″ of rich loamy soil. Portion of worms is
placed in soil and whole mass kept fairly moist. Feed slice of bread
soaked in sweet or sour milk every 3 or 4 days. Be sure all food is
covered with at least 1″ of soil. Before feeding be sure all old food is
consumed. They may be fed cooked oatmeal or mashed potatoes
WITHOUT SALT. Stir soil once a week to aerate it and prevent souring.
Cover soil with piece of glass to keep moisture in. Keep in cool dark
place.

BRINE SHRIMP—To raise Egglaying Fish, the use of Brine Shrimp


(fig. 5) replaces the old fashioned Infusoria method more and more.
Brine Shrimp Eggs are available in any good pet shop and are easily
hatched. Directions for hatching Brine Shrimp Eggs are found on
package.

33

You might also like