C Class Design Handbook Coding Effective Classes 1st Edition Richard Conway download
C Class Design Handbook Coding Effective Classes 1st Edition Richard Conway download
https://ebookgate.com/product/c-class-design-handbook-coding-
effective-classes-1st-edition-richard-conway/
https://ebookgate.com/product/combinatorial-matrix-classes-1st-
edition-richard-a-brualdi/
https://ebookgate.com/product/solutions-microelectronic-circuit-
design-3rd-edition-richard-c-jaeger/
https://ebookgate.com/product/adaptive-code-via-c-agile-coding-
with-design-patterns-and-solid-principles-1st-edition-gary-
mclean-hall/
https://ebookgate.com/product/fast-and-effective-embedded-
systems-design-1st-edition-rob-toulson/
Effective C 50 Specific Ways to Improve Your C 1st
Edition Bill Wagner
https://ebookgate.com/product/effective-c-50-specific-ways-to-
improve-your-c-1st-edition-bill-wagner/
https://ebookgate.com/product/designing-interfaces-patterns-for-
effective-interaction-design-3rd-edition-tidwell/
https://ebookgate.com/product/designing-interfaces-patterns-for-
effective-interaction-design-1st-edition-edition-jenifer-tidwell/
https://ebookgate.com/product/effective-site-investigation-
second-edition-edition-c-r-i-clayton/
https://ebookgate.com/product/product-design-and-factory-
development-the-handbook-of-manufacturing-engineering-second-
edition-volume-1-richard-crowson/
C# Class Design Handbook:
Coding Effective Classes
This book takes a top-down look at what exactly makes up a class in .NET. It
begins by defining a type and how classes relate to the .NET type framework.
It then examines what makes up types: type members. The majority of the book
is devoted to looking at the different mechanisms C# provides for defining type
members (methods, constructors, properties, operators, and events) and
examining how types combine to make up assemblies.
Summary of Contents
Introduction
Chapter 1: Defining Types
Chapter 2: Type Members
Chapter 3: Methods
Chapter 4: Properties and Operators
Chapter 5: Constructors and the Object Lifecycle
Chapter 6: Events and Delegates
Chapter 7: Inheritance and Polymorphism
Chapter 8: Code Organization and Metadata
Appendix A: Support, Errata, and Code Download
Index
C# Class Design Handbook:
Coding Effective Classes
Richard Conway
Teun Duynstee
Ben Hyrman
Roger Rowland
James Speer of Charteris pIc
A l l rights r e s e r v e d . N o p a r t o f this w o r k m a y b e r e p r o d u c e d o r t r a n s m i t t e d i n a n y f o r m
or b y a n y means, electronic o r mechanical, i n c l u d i n g p h o t o c o p y i n g , recording, o r b y
a n y i n f o r m a t i o n storage o r r e t r i e v a l system, w i t h o u t t h e p r i o r w r i t t e n p e r m i s s i o n o f t h e
copyright o w n e r a n d the publisher.
T r a d e m a r k e d n a m e s m a y a p p e a r i n this b o o k . Rather t h a n u s e a t r a d e m a r k s y m b o l
w i t h every occurrence o f a trademarked name, w e use the names o n l y i n a n editorial
fashion a n d t o the benefit o f the trademark owner, w i t h n o intention o f infringement o f
the trademark.
He can be contacted at
richard [email protected].
leun Duynstee
Teun Duynstee lives in the Netherlands. He works
with Macaw as a lead software developer and
loves programming, his girlfriend Marjolein, and
Arnie the cat.
Ben Hyrman
Ben works as a Program Architect for Best Buy, in
tropical Minneapolis, Minnesota. Ben enjoys the
balmy Minnesota weather with his loving wife,
Dawn, and an overactive mutt of a dog, Bandit.
When they're not busy with work or off on road
trips, Ben and Dawn enjoy painting their house
and arguing over database design patterns.
Roger Rowland
Roger Rowland is a freelance IT Consultant based
in the UK. He has 25 years of software
development experience on a variety of platforms,
and is a regular contributor to the Wrox C# Today
web site. He currently specializes in Microsoft
technologies including YC++, VB, C#, SQL, and
ASP. Roger is a member of the Institution of
Analysts and Programmers, a professional member
of the British Computer Society, and a member of
the IEEE Computer Society. He holds a Masters
Degree in computing and is currently undertaking
a part-time PhD at the University of East Anglia
researching into medical imaging and computer
assisted surgery. Research techniques include 3D
graphics and volume rendering using OpenGL,
and he has published a number of academic
papers. Married, with two children and always
incredibly busy, Roger may nevertheless be
contacted at [email protected].
James Speer of Charteris pic
James has been a software developer since 1987,
beginning his career programming in BCPL and
C++. He currently specializes in distributed .NET
component development, particularly - C#, .NET
Remoting, Serviced Components and MSMQ.
James is currently employed by Charteris pic
(www.charteris.com) as a Senior Developer and can
be reached at [email protected].
Introduction 1
Who Is This Book For? 2
What Does This Book Cover? 2
What Doesn't It Cover? 2
What Will You Learn? 3
What Do You Need? 4
Value Types 15
Primitive Types 16
Viewing the Output from the Compiler 19
User-Defined Value Types (Structures) 22
Defining and Using Value Types 23
Using Inheritance with Value Types 25
Enumerations 28
Enumerated Types 28
Bit Rags 30
Inside an Enumerated Type 32
Reference Types 33
Class Types 34
Defining Classes in C# 34
Defining Accessibility for Classes 37
Nested Classes 38
Creating and Disposing of Class Objects 40
Table of Contents
Delegates 41
Arrays 42
Declaring Arrays 42
Initializing Array Elements 42
Using Arrays 43
Casting Arrays 44
Strings 45
Declaring Strings 45
Strings are Immutable 45
Using Strings 46
Interfaces 51
Summary 52
Fields 62
Properties 64
Methods 67
Method Overloading 67
Properties versus Methods 68
Static Type Members 69
Events and Delegates 72
Operators 73
Constructors 73
Destructors 74
Working with System.ObJect 75
GetTypeO 75
ToStringO 76
EqualsO 78
GetHashCodeO 80
EqualsO and GetHashCodeO 81
Summary 82
ii
Table of Contents
Chapter 3: Methods 85
Invoking Methods 85
Method Scope and Visibility 87
Method Types 87
Instance and Static Method Example 88
Instance and Static Method Best Practice 89
Arguments and Parameterized Methods 90
Parameter Types 90
Passing by Value 90
Passing by Reference 91
Output Parameters 93
Passing Reference Types versus Value Types 95
Passing Value Types by Value 96
Passing Value Types by Reference 98
Passing Reference Types by Value 99
Passing Reference Types by Reference 102
Variable Length Parameter Lists 103
Passing Strings - Immutable Objects 105
Passing Arrays and Upper Bound Checking 106
Passing Enumerated Values 106
Method Overloading 106
Exception Handling 110
What Is an Exception? 111
Try ...Catch ... Finally 112
Throwing Your Own Exceptions 113
Methods and MSIL Code 117
Design Summary 123
iii
Table of Contents
Operators In C# 151
Operators are in Fact Expressions 151
Operator Overloading Syntax 152
Operators and Classes 154
Compiling Operators into MSIL 157
Operator Overload and Cross-Language Support 159
Symmetrical Operator Overloads 160
Type Comparison and Equality 161
Operators and Structures 166
Operator Overloading in Pairs 169
Operator Overload Best Practice 171
Operators Summary 171
Summary 172
iv
Table of Contents
v
Table of Contents
Metadata 316
Viewing Metadata in a Single-File Assembly 317
Creating Multi-File Assemblies 322
Index 353
vi
Table of Contents
vii
C#"
Introduction
C# is a language that follows in a grand tradition of programming language design; it
draws its influences from C++ and Java, and even Delphi and Visual Basic - a rich
inheritance, which provides it with much that is familiar to many developers, but also
much that is alien or unexpected.
This book takes the lid off C#'s object-oriented model, and examines how we use C#
as a language for creating classes (and, indeed, other kinds of types). Since everything
we code in C# is a type, all our logic belongs to methods of types, and the state of our
program at any moment is tied up in the values stored in the fields of instances of
types in memory. A good understanding of how to create those types is therefore
fundamental to good C# programming.
We'll explore what options C# gives us in declaring types and type members in our
code, and the impact our decisions will have on code that uses our types. We'll see
how we can code differently when our types are for public use, and when types are
for use within our own code. We'll look at what we can do to ensure our types are
only used in ways we design for, and how we can expose functionality from our types
in a consistent, logical, predictable, and user-friendly manner, for other code to exploit.
Introduction
This book assumes you're already coding with C#, you're already familiar with the
basic syntax, and you're regularly writing code that works. You should be familiar with
your chosen development tools and know how to compile and run C# code.
You should be aware of .NET's basic object-orientation mechanisms - for example, that
objects are instances of classes, how objects are instantiated, and how methods and
properties on an object are accessed. We'll recap on the meaning and syntax of most of
C#'s class construction keywords as we discuss them, however.
This book takes a step back from the code we write every day and asks, "What is it really
doing?" It asks you not to consider each C# keyword or syntax construction just in terms of
its effect, but to consider how it accomplishes that effect. In the course of this book, we'll
see how all our code is compiled into .NET types; how we defme type members; how type
members are inherited; how types are aggregated into assemblies; how we can control the
creation of instances of types; and many more aspects of effective class coding.
2
What Will You Learn?
3
Introduction
http://msdn.microsoft.com/downloadS/sample.asp?
uri =/msdn-fileS/027/000/976/msdncompositedoc.xml
Q A version of Visual Studio .NET that incorporates Visual C# .NET. The 2002
edition of the Visual C# .NET IDE is included with the following
Microsoft products:
• Microsoft Visual C# .NET Standard
• Microsoft Visual Studio .NET Enterprise Architect
4
What Do You Need?
There are several .NET implementations for other platforms undelWay, and support for
C# compilation on Linux, UNIX, and Windows is provided by the Mono project
(http://www.go-mono.com/).MonocodedoesnothaveaccesstothefullMicrosoft.NET
class library, but follows the same syntactic rules as Microsoft's C#, meaning the lessons
in this book should apply in equal measure.
5
C#"
Defining Types
C# is an object-oriented programming language, and one of the principles which guide
its design is type safety. During object-oriented analysis and deSign, we identify the most
important objects in our system, and consider how they will relate to each other. When
we program in C#, classes are the main mechanism we use to define the behavior of the
objects that will exist in our program at run time. However, C# offers us a great many
ways to package up the code that defines our application - and not just in classes.
Whenever we code in C#, though, what we write are always types, and these types
represent a combination of behavior and data storage requirements. When the program
runs, it creates instances of types (which allocate the data storage required), and makes
available the features of the types. Within the .NET environment, type-safe code only
accesses the memory locations it is authorized to access and types interact only in
well-defined, permitted ways. This is important for producing secure, stable applications
that ensure even badly written code can't do too much damage, and plays by the rules.
This book aims to help C# developers gain a deeper and more confident under:standing
of how to build well designed classes that will behave correctly and consistently within
the .NET Framework. Through exploration and examples, we will give you an
awareness of the consequences of decisions made during the design and development
phases, and will point out any not-so-obvious similarities with or differences from other
object-oriented languages like C++ and Java.
We'll begin this book by looking at what exactly a type is. In this chapter, we'll
examine .NET's type system, and the kinds of type available to us as developers.
Chapter 1: Defining Types
Types
In programming, we use the term 'type' to describe a particular kind of value. For
example, C++ and Java programmers will be familiar with types such as int, float,
and double. For each type, the compiler knows the following information:
C++ Note: Having been used to defining the interfaces ofyour c++ classes
in header files, you will already be aware that C# has no headerfiles. The
definition of c# types is included in the compiled assembly as metadata.
You should also remember that the C# compiler does not worry about the
order of type declarations in your source code.
To a computer all data is just chains of ones and zeroes. When we have a variable in
our program, ultimately that variable is simply holding a binary number of some kind.
So, when we ask the computer to display that variable on the screen, perform a
calculation on it, or retrieve one of the variable's properties, the computer needs to
know what type the variable contains in order to know how to interpret its value, and
thus respond to our request. For example, an integer and a single-precision floating-
point number can both be stored in four bytes of binary data. Take the following four
bytes, for example:
If the value were interpreted as an integer, it would represent the number 920,357,492.
Interpreted as a single-precision floating-point value, it has the approximate value of
6.5428267E-6. So, if a variable contains this binary number, and we ask .NET to add
one to it, the result is going to depend not only on what value is in the variable, but
also on the variable type.
A type describes the purpose of any string of ones and zeroes in memory. It enables us
to compare values of two integers and see if one is greater than another, retrieve a
string representing a value, or modify the value in a particular way.
8
Types
Figure 1
J ! classes I
struct~ ~xedvalue~
The diagram shows how the Common Type System makes a clear distinction between
value types and reference types, which are discussed below. It also allows us to define
pure interfaces; an interface is a simple definition of a contract, which is then implemented
by another type (or types) - it separates out the defmition of a contract from the
implementation of that contract. All of the other types combine the above two things.
c++ Note: Intetfaces are akin to pure abstract classes. Unlike in C++, a C#
class may only inherit from a single base class. However, a C# class may
additionally inherit from multiple intetfaces.
9
Chapter 1: Defining Types
The CLS makes it extremely easy to use several different programming languages in the
same application. Whenever we compile source code written in a CLS-compliant
language, it is compiled into a standard .NET Framework byte code format called
Microsoft Intermediate Language (MSIL). The CLS ensures that certain types and
language constructs are all compiled to the same MSIL equivalents whatever the
language used. This means we can easily mix-and-match C#, Visual Basic .NET,
Managed Extensions for C++, Visual J#, or JScript .NET within the same application,
provided we only use CLS compliant types in any public interfaces declared in our
code. To ensure this, the C# compiler can be instructed to check the code and issue
warnings if we break any rules.
The use of an intermediate byte code format will be familiar to Java developers. Just as
Java is typically compiled to byte code before being run in a managed environment
(the Java Virtual Machine), so are C# and other .NET languages compiled to MSIL
before being run by the .NET Common Language Runtime (CLR). One difference is that
Java optionally allows the byte code to be interpreted at run time rather than compiled
to native code, while MSIL is always compiled, either by the Just In Time compiler
(JIT), or as a pre-JITted assembly loaded from the Global Assembly Cache (GAC). The
other important difference is that the language-neutral nature of MSIL was designed
into the .NET Framework from day one. As mentioned earlier, the CLS effectively
specifies a set of rules that define how different languages should compile to MSIL and
this facilitates language interoperability.
10
Types
It is also worth pointing out here that language interoperability is not just a girrunick. The
CTS and .NET runtime together support many more features than the subset defmed by
the CLS. Different languages expose different, larger subsets of these features, though at
times they overlap. So it is possible that a particular language may be more suitable for
certain parts of an application. As all languages share the common ground defined by the
CLS, we have a guaranteed interface between these languages.
Apart from .NET languages, there are also a number of CLS-compliant languages from
third-party vendors, such as COBOL (Fujitsu), Perl and Python (ActiveState), and
Smalltalk (Quasar Knowledge Systems).
Before we look at the details of value types and reference types, it's useful to know
that all the types in .NET are completely self-describing. This includes things such as
enumerations and interfaces. A compiled .NET assembly (an . exe or a . dll) includes
metadata, in which all the details of the types defined and used by the assembly are
given. For those types defined in the assembly, we can use reflection to interrogate
their definition. This is useful during development, where we don't need header files or
type libraries to identify what properties and methods an object exposes. It is also
crucial at run time, where the CLR uses this information to dynamically resolve method
calls during JIT compilation. This information is stored in a compiled .NET assembly
and is used extensively by the CLR. We'll cover metadata in more detail in Chapter 8.
Since this value type actually consists of very little data, it is easy to pass DateTirne
information around in a program. If we create a variable aDate to hold a DateTirne, it
will need eight bytes of storage exactly. If we create another variable bDate to hold a
DateTirne, it too will take eight bytes of storage. If we now write bDate = aDa te; ,
the eight bytes of data in aDate can be quickly copied and placed into bDate.
11
Chapter 1: Defining Types
When used as local variables or member fields, value types are allocated on the stack.
This is an efficient (but limited size) area of memory used strictly for storing local
variables (variables declared inside method bodies). The effect of the above actions
may be shown schematically as follows. First, we declare two DateTime value types
representing different dates:
The effect on the running thread's stack is shown in the following diagram. On the left is
the situation immediately before the copy, and on the right is the situation after the copy.
Figure 2
St ck
Value types exhibit copy-by-value semantics; when we copy one value type object to
another, the compiler performs a byte-by-byte copy of our object. Value types are useful
when we don't care how many copies of an object we create; all we care about is the
value. When we pass a value type object into a method, the compiler creates a local copy
of the object. When the method returns, the memory that the local copy of the value type
object was using is automatically reclaimed. This means there are some important
limitations to the kinds of uses to which we can put value types.
12
Types
The managed heap is a much larger area of memory than the stack but is slower to
access. This is similar to a C runtime heap except that we only use it to allocate
memory; we never specifically free memory from the managed heap. The CLR handles
all of this housekeeping automatically (hence the term managed).
If we create an array of eight integers (which will require 32 bytes of space to store the
array's members), it is created by allocating 32 bytes of the managed heap. When we
place that array into the myArray variable, the location of the array on the managed
heap (a reference to the array) is placed into the variable itself. The myArray variable
that contains this reference is (like all local variables) held on the stack. The memory
pointed to by the reference is on the managed heap.
If we then create another variable myArray2 to hold an array of integers, and then
write myArray2 = myArray;, the value of that reference is copied into myArray2 so
that it points to exactly the same array of integers that myArray did. Arrays, like all
classes, are reference types.
We can see this happening schematically. First, we define two array variables,
initializing one of them to refer to a new instance on the managed heap:
Then, we'll assign one array to the other. Remember, this only copies the reference:
MyArray2 = myArray;
The result of these operations is shown in the following diagram. On the left, we have
the running thread's stack and the managed heap immediately before the above
assignment; on the right the situation is shown after the assignment. Note that the
reference variables myArray and myArray2 now both refer to the same array instance:
Figure 3
I ref J
I
I ref J II
rTrfArray2 1\
I null I
13
Chapter 1: Defining Types
So, reference types represent entities that have a unique identity - they exist in one place
on the managed heap, and are referenced from variables using this identity. When we
defined an integer array and created an instance of this, the CLR allocated memory for
the object and returned us a reference to this new object. When we copied the array into
another variable, we just copied the reference. We still only have a single Array
instance, but there are now two variables referring to it. Reference types exhibit copy-by-
reference semantics. Likewise, when we pass a reference type into a method, the
method receives a copy of the reference to our object, not a copy of its value.
Where reference types are concerned, C++ developers will need to get used to not
thinking in terms of pointers. Although this is more-or-less what happens behind the
scenes, the CLR moves objects around on the managed heap and adjusts references on
the fly while the application is running. Since we don't notice this at run time and it's not
obvious from the source code, it confuses matters if you mentally try to translate between
C# and C++ as you write. For example, in C# the syntax for accessing a value type is no
different from that for accessing a reference type. In C++ you might have the following
However, in C#, the '->' syntax is only used in unsafe code blocks for backward
compatibility. In normal situations, the ' . ' should be used to access the type's methods
as follows
14
Value Types
Note also that we do not explicitly delete the heap-allocated variable when we have
finished with it. We just nullify the reference and leave the rest to the garbage collector.
Once the garbage collector determines that the object is no longer accessible through a
reference stored anywhere else, it will become eligible for disposal. This will be familiar to
Java and Visual Basic developers but may look like sloppy code to a C++ developer. This is
discussed in more detail in Chapter 5 where we'll be looking at the object lifecycle.
InitiaHzing Variables
When a variable of any type is created, it must be initialized with a value before being
accessed. If we forget to put a value into a local variable and then try to use that variable
in a calculation, the C# compiler will give an error. This is very different from C++ where
it is the programmer's responsibility to check for this problem, and from Visual Basic
where local variables are automatically initialized to suitable default values.
The only case in which the C# compiler will initialize variables on your behalf is for
variables declared as fields in a class or struct. This simple compile-time check can
save hours of debugging as it prevents you inadvertently retrieving junk values from
memory left over from other programs.
Everything is an Object
It is important to remember here that any type within the .NET environment, whether a
value or reference type, is an object. This means that every type will inherit explicitly,
implicitly, or indirectly from System.Object. This is similar to the situation in Java,
where there is a single rooted class hierarchy, with every class inheriting in some
manner from java . lang . Obj ect - except that in .NET it also applies to non-
reference types. We'll explore some of the consequences of this throughout the book.
Value Types
There are three main kinds of .NET value types. In this section, we'll discuss each of
these in some depth:
o Primitive types
All programming languages define primitive types such as integers,
floating-point numbers, and so on. In .NET, such types are value types.
We'll discuss the primitive types in C#, and see how these types map to
Microsoft Intermediate Language (MSIL) data types.
o User-defined value types
We can define our own value types to represent simple objects or small
pieces of data in our application. In C#, structures are user-defined value
types, and are defined using the struct keyword. The .NET Framework
defines custom value types, such as System. DateTime and
System. Drawing. Point, in a similar manner.
15
Chapter 1: Defining Types
o Enumerations
An enumeration is a special kind of value type, which represents a type
that has a small list of allowable values. An enumeration might specify the
values Yes, No, and Maybe for example. Underneath, each of these values
is normally represented by an integer, but defining an enumeration type
allows us to assign meanings to a specific set of integral values.
Unlike Java, both C++ and Visual Basic already support enumerations. The
big difference with C# is that enumerations in the .NET world are strongly
typed. For example, we might have a HairColor enumeration that allows
Blonde, Red, Brown, and Black, and an EyeColor enumeration that can
be Blue, Green, or Brown. This allows us to write readable code, while still
ensuring that we can't aCcidentally give someone blue hair and red eyes.
Primitive Types
c# defmes fifteen primitive types to represent integral numbers, floating-point numbers,
Boolean values, and characters. Eleven of these primitive types are defined by the CLS to
be interoperable with any other CLS-compliant programming language. The remaining
four types are not CLS-compliant, so can only be used in private sections of a C#
application or in any public interfaces where language interoperability is not required.
Each of these primitive types is actually just a synonym for a standard type in the .NET
Framework's System namespace. There is no effective difference between a value type
we define ourselves, and one of these special primitive types. However, these types do
benefit from some special support in the C# language:
o literal syntax: primitive values can all be created using a literal syntax. For
example, when we write float pi = 3.142 f; we are using a literal to
specify a floating-point value. We could use 3 .142d to indicate a double, or
any of a range of suffixes to identify other numeric types. Similar notations
exist for other primitive types, like true and false for Boolean literals.
o Operator support: primitive types can be combined using special operators.
So we can use an addition operator (+) to add two numerical values, or the
'&' or 'I' operators to combine Booleans. In C#, it is also possible to define
operators for our own types. We'll cover this in depth in Chapter 4.
The following table shows the mapping between C# primitive types and the equivalent
structures in the Sys tern namespace. The table also shows how the C# .NET compiler
translates these types into Microsoft Intermediate Language (MSIL) data types during
compilation. Non-CLS-compliant types are marked with an asterisk:
16
Value Types
Notice that C# actually lists string and object as primitive types, although both of
these are reference types, not value types. As obj ect is the root of the whole .NET
class hierarchy we'll discuss System.Object further in Chapter 2. However, while most
programming languages include some form of string as a primitive type, the .NET
Framework takes a slightly different approach. For now, we'll use this section to look
at those primitives implemented as value types, and we'll discuss strings when we look
at reference types a little later.
C and C++ developers should be aware that the descriptions given in the table for the
C# primitive types will always be consistent within the .NET Framework. In particular,
in C#, an int is always 32 bits. In C/C++ the size of an int is platform dependent-
although this is commonly overlooked. Similarly, in C#, a long is 64 bits, where in C++
long represents "an integral type that is larger than or equal to the size of type int".
These definitions obviously apply right across all of the .NET languages and this leaves
a little less scope for error when operating in a mixed-language environment.
17
Chapter 1: Defining Types
As all types in .NET are objects, we can even invoke methods on literals. This may
seem strange and you'd probably never want to do it, but if we consider a line of code
like string s = 32. ToString () ;, compile and run it, it should help fix in your mind
the "everything is an object" message.
The following simple console application illustrates the use of primitive types in C#:
using Sy tern;
class MyCla s
(
static void Main()
(
int i 100; II use a primitive C. typ
Int32 j • i; /1 use the equivalent .NET Fram ork type
We can use primitive C# data types (such as int) interchangeably with the equivalent
.NET Framework types (such as System. Int32). For the sake of simplicity and
familiarity, you should stick to one set of declarations in your code.
We use the typeof operator to obtain information about data types at run time and
write this information to the console. The following code asks the user for a numerator
and a denominator and then calculates the quotient.
18
Value Types
We use various methods defined in the Double type to read and process double
values in our application. The Parse method extracts a double value from a string;
IsNaN () tests for "is not a number"; IsPositivelnfinity () tests for positive
infinity (for example, dividing 100 by 0); and IsNegati velnfini ty () tests for
negative infinity (for example, dividing -100 by 0).
When the application runs, it displays the types for int and Int32 as System. Int32;
this confirms that the int type in C# .NET is just another name for System. Int32. The
application also asks us to enter two floating-point numbers; if we enter some arbitrary
numbers, we can see the output on the console.
Save the code into a file called primi ti ve_types. cs, and compile it. Now enter the
following at the command prompt:
19
Chapter 1: Defining Types
Some developers dismiss the MSIL Disassembler as being irrelevant and over-hyped,
but that's not the case. We'll be using the MSIL Disassembler extensively in this book,
to investigate how the C# .NET compiler has compiled our code.
To run the MSIL Disassembler tool, open a command prompt (if you are using Visual
Studio .NET, make sure you start a Visual Studio .NET command prompt), then move
to the folder that contains the executable file, and run ildasrn as follows:
The name and location of the executable file depends on how we built the application:
D If we built the application using Visual Studio .NET, the executable file will
have the same name as the project - although with an . exe or . dll
extension - and will be located in the bin\Debug or bin\Release sub-
folder. Also, Visual Studio .NET adds a namespace, which is the same as
the project name.
D If we built the application using the command-line C# compiler, the executable
me will have the same name as the source me, again with an . exe or . dll
extension, and will be located in the same folder as the source me.
For example, if we built the prirni ti ve_types application using the command-line
compiler, we could load up prirni ti ve_types . exe into the MSIL Disassembler.
When you expand the MyClass icon, the MSIL Disassembler window displays the
following information:
..-_---
. WW!J
... ""'
~ ..... NlfEST
. ~,a...
~ ".pN"'No""btIOI~
• do<-o
•
.......tIt< _ _ _
(
I:A
~ .~. -'~'-'~'~''';-'-P'~'-'- 'J·~="-'d.!J
Double-click the Main icon, to open a view of the MSIL code for the Main method:
20
Value Types
... tr~patnt
.• u<taR In<unu void [ .... a.I1D)S~st ... ST.Th ...d.ttr1DuU:: .• terO •
1/ taU sin 119 I .. Dd)
.ux5tiCk :J
.10 •• 1. lolt (1nU2 V .,
int32 U 1, -
string U_ 2,
flu.t.1I IS 3,
Flootn u- _.
flootn u: S)
Il .... : lde.I_.$ 1..
Il-"I2: sUae.' I
Il: . 13: Idloe ••
Il "A: sUoe.l
Il- IIIS: IdUr "int : (II"
Il- .... : ldto~.n [ ... eorIIDI$~n •• ,lntI2
Il: ..I : caU ..... 1..... rllbl$jJst ••. T~p. 1..... rIlDISl/
t ••• Tl/p,::C"
Il_ " " : uUvirt lnst.nc. string l ... eo.UDlSjJsto •• Typ.: :g.tJulllY.<)
Il_ "19: nil uald [ .. earl1b)S~.t ••. Can.olo: :lIrtt.L!n.( t.lng,
ObJ •• t)
Il I.,.: IdUr "lnt32: (I)"
.( -
In the MSIL code, the Main () method is marked with the MSIL managed keyword.
This indicates code that runs in the managed environment provided by the .NET
Framework Common Language Runtime. All code we write in C# will be managed
code. A variety of local variables can be found described with MSIL data types such as
float64, int32, and string.
Let's look at the end of the IL code for the Main () method:
j
IL-DD98: call Dool (lIScorl1blSl/sto".Doublo:: ISH@gaUuolnflnitylflo.,
1L:.D9d: brfaIsl!I.s Il D.. b
Il ID9f: Idstr "~g.t1v. Infinitl/,"
IL-I"~: call void (lOScorllblSysto ... Cansolo: :Writ,Un.(string)
IL-U.9: br.s IL lillie
Il-nab: ldstr "R'.uIt is (I)."
IL -alibI: ldl.e .s us
Il-OOb2: box [iiseorl1blSlIst... Doubl.
1l:11lII7: call void ( ... corl1blSyst... ConsolO: :lIritolino(strlng.
obJ.et)
IL IDDe: ret
) ,,-.nd of .... thod MyCh .. ::lYln
~=-~==~===="~~==.~.-~~.-~~~ ~~~~~~~~~~~~~ . ~
Each line of IL code consists of a command, followed by any data the command needs to
operate on. Data that the program is working with is stored on the stack. Items are loaded
onto the stack using lL commands that begin Id for load. Each variable on the stack takes
up a fixed amount of memory defmed by its type. For reference type objects, the stack
contains a reference to the location on the managed heap where the actual object is stored,
21
Chapter 1: Defining Types
The first line in the screenshot loads a reference to a string onto the stack. The next
loads the contents of the variable V_5 (which contains the result of the division
operation) onto the stack. When an item is placed on the stack, it goes on top of any
previous stack items. When items are taken off the stack, the top item is removed first.
We'll ignore the box command for a moment, and instead look at the call command.
This call tells .NET to call a method, called Wri teLine ( ) , belonging to a class called
System. Console, found in the mscorlib.dll assembly, which takes as arguments a
string and an object .. NET looks up this method, takes the two items from the top
of the stack and passes them to the method being called. The top item on the stack is
our floating-point value, which is a result of the division we performed. This is not an
obj ect, it's a value type.
We'll look at boxing in depth later as there are some important performance
considerations. For now, we just need to know that the box instruction in the IL code
takes the item on the top of the stack, copies it to the managed heap, and places on
the top of the stack a reference to the boxed value. This allows us to treat the value as
an obj ect and pass it in to this method call. So, when the call to the method comes,
the items on the top of the stack are a boxed value and then a string, and these two
values are passed to the Console. Wri teLine method.
Close the MSIL Disassembler windows when you have finished. if you
forget to close the MSIL Disassembler windows, the EXEfile will remain
locked by the MSIL Disassembler. ifyou try to recompile the application
with these windows open, you 'll get a compiler error because the EXE file
cannot be overwritten.
22
Value Types
Because of the way value instances are passed around, value types should ideally be
small. If we define large value types, inefficiencies start to creep in when we pass the
value instances between methods in our application because of the amount of data that
has to be copied into and out of the method. Large value types will slow down the
allocation, management, and cleanup of objects and stack frames that use them.
In this section, we'll see how to define and use value types effectively in C# and how
to use inheritance with value types.
Value types, or structures, are cut-down classes, although there are some
important differences:
23
Chapter 1: Defining Types
using system;
struct Money
(
// private instance field
private int centsAmount;
// public constructor
public Money(int dollars. int cents)
{
centsAmount = (dollars • 100) + cents;
24
Value Types
class MyClass
(
static void Main()
(
Mon y fr eoie;
Money salary = new Money(20000. 0);
Money carP rice = new Money(34999.95);
At the moment, this program doesn't provide any evidence that it's working. We'll add
some more functionality to it in the next section.
When we define our own value types, we can override some of the methods inherited
from System. ValueType or System. Object. One of the most commonly overridden
methods is ToString () , which returns a string representation of the object. For more
information about System. Object, see Chapter 2.
25
Chapter 1: Defining Types
Structures cannot be used as base classes for other classes to inherit; they are not
extensible through inheritance. Structures can be very sophisticated types but they are
not classes. This language restriction enables the compiler to minimize the amount of
administrative code it has to generate to support structures.
Although structures cannot explicitly inherit from an arbitrary class, they can implement
interfaces. For example, it is quite common to implement standard .NET Framework
interfaces such as IComparable, which allows us to specify how objects should be
compared, and so enables sorting. Value types will often implement this to interoperate
well with other classes in the .NET Framework.
We'll be covering interfaces in more detail later in this chapter, but the following preview
demonstrates how easily we can change our Money value type to implement an interface,
and override the ToString () method inherited from System. Object:
II value_type_inheritance.cs
using System;
II public constructors
public Money(int dollars, int cents)
26
Value Types
The Money structure now implements the IComparable interface. The CornpareTo ( )
method, as specified by the ICornparable interface, compares the value of this Money
instance against another Money instance, and returns an integer to indicate the result of
the comparison.
class MyClass
(
static void Main()
(
II create an array of 5 items
Money[) salaries = new Money[5];
salaries [0) new Money(9.S0);
salaries[l] new Money(4.80);
salaries(2) new Money(8.70);
salaries(3) salaries!2];
salaries (4) new Money(6.30);
In the above example, the Main () method creates an array of Money instances, and
when array element 3 is assigned the value of element 2, it obtains a copy of the value
of element 2. Each Money instance in the array is displayed using
Console. Wri teLine, which implicitly invokes our overridden ToString () method.
The Array. Sort () method sorts the array. For this to work, the array elements must
implement the IComparable interface. Array. Sort () calls the CompareTo ()
method repeatedly on the array elements, to sort them in the specified order. Finally,
the sorted array is displayed on the console.
27
Chapter 1: Defining Types
Sorted array:
$4.8
$6.3
$8.7
$8.7
$9.5
Enumerations
Enumerations are .NET value types that represent integral types with a limited set of
permitted values. They may also be used to map bit flags onto an integer type to allow
a convenient way to represent a combination of options using a single variable.
Enumerations are present in many programming languages, but in .NET they are also
object-oriented. This means that developers now have access to additional features,
which are not present in other languages.
Enumerated Types
To declare an enumerated type, we use the enum keyword and specify symbolic names
to represent the allowable values. We can also specify an underlying integral data type
to be used for the enumeration (byte, short , int , or long), and optionally assign a
specific number to each of the names.
II enumerations.cs
using System;
Enumerations inherit implicitly from System. Enum, and so inherit all of its members.
Having defined an enumerated type, we can use it in our code as follows :
28
Discovering Diverse Content Through
Random Scribd Documents
§ 4. Se non ucciso sul fatto, poteva l'adultero essere
punito con altre pene e tradotto in giudizio. Esigevasi però
sempre per le stesse e per la traduzione in giudizio la
flagranza. «έλήφθη μοιχὸς», Lisia, C. Agor., 26. «ἐφ ῇ ἂν
μοιχὸς ἄλω». Demost., C. Neera, 1374. — «μοιχὸς ἑάλω...
ἄνθρα ἐν ἄνθροις (membra in membris) ἒχων» Luc.,
Eunuc. — «Et hoc est quod Solon et Draco dicunt: ἐν
ἒργῳ». Ulpiano.
§ 5. La flagranza riguardava l'adulterio non solo
consumato, ma anche tentato, e non compiuto per
circostanza indipendente dalla volontà dell'adultero.
«Punisce la legge come adultero non solo chi commise in
fatto l'adulterio ma anche chi lo volle o tentò
(βουληδέντα)» — Massimo Tir., Diss. ii.
§ 6. Il marito che non uccide l'adultero, e intende punirlo
d'altra pena, si impossessa della persona dell'adultero
legandolo: o rilasciandolo libero, solo dietro malleveria. Su
la legittimità della cattura, e quindi sul merito dell'accusa
d'adulterio, decide il tribunale. «Se alcuno avrà messo
ingiustamente i lacci ad un altro come adultero, questi lo
accusi ai Tesmoteti: e se vincerà e apparirà legato
ingiustamente, sia libero, e sciolti i mallevadori da obbligo;
se invece è chiarito adultero, i mallevadori riconsegninlo
all'accusatore». — Dem., C. Neera, 1367.
§ 7. Le pene sussidiarie, in luogo e vece dell'uccisione,
sono a piacer del marito o pecuniarie o corporali. Può il
marito accontentarsi di una multa. «È legge l'adultero
multarsi in danaro». Ermogen., De invent., II, 1. — «È
legge l'adultero pagare o morire». — Auct. Probl. Rhet. «E
quegli (l'adultero Eratostene) mi prega, mi supplica di non
ucciderlo, ma di ricever denaro in componimento». Lisia,
Ucc. Erat., 25. «Stefano sorprende Epeneto come adultero
e gli estorce trenta mine: delle quali avuti mallevadori,
lasciò andar libero Epeneto, tenendosi certo del danaro».
Dem., C. Neera, 1367.
§ 8. Le pene corporali, in luogo dell'uccisione, potean
essere di vario genere a piacer del marito: e inflitte nello
stesso recinto del tribunale giudicante sulla legittimità
della cattura. «Se è chiarito adultero, i mallevadori
riconsegninlo all'accusatore, il quale, lì nello stesso
tribunale può far su di lui, purchè senza spada, ciò che
vuole, secondo conviensi ad adultero». (ἄνευ ἐγχειριδιου
χρῆσθαι ὄ τι ἄν βουληθῆ ως μοιχῳ). Demost., C. Neera,
1367.
§ 9. Nella antecedente designazione sono comprese le
pene:
α. dell'accecamento. «Stabiliva la legge potersi
impunemente accecare (τυφλοῦσθαι) l'adultero colto in
fatto». Auct., Probl. Reth., c. 58. «Adulteros deprehensos
licet excœcare». Cur. Fortunatianus, Rhet. Scol.
β. del marchio rovente. «ἔξεστι στιξειν τοὺς μοιχούς».
Hermog., Part. Stat. — νόμος τὸν μοιχὸν στιξειν.
Marcellinus.
γ. del rafano (ῥαφανιδωσις). Faceasi star carponi l'adultero
e pelategli le natiche con cenere calda, gli si ficcava nel
podice un rafano de' più grandi. Suida, alle voci
ραφανιδωθὴναι e μοιχὸς. — Alcifr., Lett., III, 62. — In
luogo di un rafano si usava anche un pesce detto mugile.
Catullo, carm. XV.
§ 10. Il marito che uccide con pene corporali l'adultero
non ucciso sul fatto, risponde di omicidio. — ἄνευ
ἐγχειριδίου, Demost., C. Neer., loc. cit. «Chi bollando
l'adultero, lo uccide, è reo di omicidio». Hermog. e Marcell.,
loc. cit.
§ 11. È condannato il medico che cura gli adulteri,
castigati col marchio o col rafano. «’Ιατρὸς, τὰ τῶν μοιχῶν
ίώμενος στίγματα, κρίνεται» Sopater.
§ 12. Vietato è all'adultero l'ingresso ne' templi. Sop., in
Hermog.
DONNE ADULTERE.
§ 13. Lecito è uccidere l'adultero (colto sul fatto) e
l'adultera insieme. Hermog., Part. St. — Marcellinus, in
Cicer., Rhetor., ii.
§ 14. Il marito che non uccide l'adultera (colta in fatto) è
però obbligato a ripudiarla. «Quando abbia sorpreso in
fatto l'adultera, chi la sorprende non potrà più dimorare
con la moglie: e se dimorerà con essa, sia punito
d'infamia». Demost., C. Neer., 1374.
§ 15. La donna adultera ripudiata non ha dritto alla
restituzione della dote. «È legge che la dote dell'adultera
resti al marito». Sopater. Divis. Quæst. Cfr. Libanius,
Declam., 35. — «Trovando la moglie non costumata e
reputandosi ingannato, la scacciò, gravida, di casa e non
le restituì la dote». Demost., C. Neera.
§ 16. «Legge dell'adulterio. Nè alla moglie (per adulterio
ripudiata) sia lecito entrar nei pubblici templi, se è stata
trovata col drudo: e se vi entri, ognuno possa maltrattarla
a piacere, tranne che ucciderla». Demostene, C. Neer.,
1374. «Perciocchè, se una donna è stata colta con
l'adultero, non può più entrare nei templi per vedere e
supplicare, come può fare una straniera e un'ancella, a cui
lo consentono le leggi. E se le adultere vi entrano in onta
alle leggi, ognuno può maltrattarle a suo talento, purchè
non le uccida. E se la legge eccettuò la morte, mentre
volle impune ogni altro maltrattamento, questo fece
perchè non volle contaminati i templi». Demost., C. Neer.,
ibid. «Solone, dei legislatori il più glorioso, scrisse all'uso
antico decreti solenni sul buon costume delle donne.
Imperocchè alla moglie presso la quale sia stato sorpreso
l'adultero non consente adornarsi, nè entrare nei pubblici
templi, affinchè con la sua presenza non corrompa le
donne oneste. Che se vi entri e se si abbigli, ordina al
primo capitato di lacerarle le vesti e di strapparle gli
ornamenti e di batterla, purchè non la uccida nè la ferisca.
Così il legislatore vitupera questa donna e le crea una vita
peggior della morte». Eschine, C. Timarco, § 183.
§ 17. La moglie accusata d'adulterio può discolparsi dando
il giuramento d'innocenza al pozzo di Callicoro. «A
Mnesiloco Peanese scopersi le impudicizie di sua moglie:
ed egli che aveva ogni modo di appurar la cosa (o uom
proprio di zucchero!) ripose tutto nell'affar del giuramento.
Pertanto la donna condussero al pozzo di Eleusi detto
Callicoro: ivi spergiurò e del delitto purgossi». Alcifr.,
Lett., iii, 69.
SUI LENONI.
§ 18. Ai lenoni era inflitta la morte. «Solone comanda
accusarsi i lenoni, e convinti dannarsi nel capo: perchè alle
persone desiderose di peccare ma vergognose e dubbiose
di trovarsi insieme, danno sfacciatamente e per prezzo
occasione ed agio al delinquere». Eschine, C. Timarco.
202.
Vedi nota antecedente sotto il numero 11.
203.
Cfr. l'orazione di Lisia, in difesa di Eufileto, sulla Uccisione
di Eratostene.
ATTO TERZO
SCENA I.
Mènecle solo.
SCENA III.
Mènecle e Blèpo.
SCENA IV.
Seno, lo chiama!...
SCENA V.
Mènecle e Tratta.
Mèn. Alle corte. E bada a non mentire. Da quanto tempo fai questo
ufficio di... Iride messaggiera?
Tr. Che le Furie mi portino via, se non è questa soltanto la seconda
volta.
Mèn. Ah!... (frenandosi) E quando... la prima?
Tr. L'altro ieri.
Mèn. (Il cuore me lo diceva!) E, n'è vero... da Cròbilo?
Tr. Sì, padrone.
Mèn. E Aglae t'avrà detto di non dir nulla...
Tr. Oh no! niente la mi disse...
Mèn. Ed ora da Cròbilo ci tornavi...
Tr. No, no, padrone...
Mèn. Come no? Questo foglio non lo portavi a Cròbilo?
Tr. No.
Mèn. Neghi ancora? A chi dunque, sfacciata? O confessa, o...
Tr. A Elèo.
Mèn. (balzando di sorpresa) Elèo?!! Eh? O quanti ne ha? Elèo?...
(lunga pausa. Mènecle si passa la mano sulla fronte, guarda la
vecchia, guarda il papiro, fa per isvolgerlo, trema di svolgerlo,
s'arresta ancora) No... no... tu menti... non è possibile!
Tr. Buttami dalla torre del Ceràmico [207] se non è vero che ad Elèo
lo portavo...
Mèn. (con accento lungo, doloroso) Anche Elèo!... (si copre,
angosciato, delle mani il volto: poi, cupo, a Tratta) Va. Più tardi con
te aggiusteremo i conti... Blèpo!... (a Blèpo che si affaccia) Tieni
costei sotto custodia!...
Tr. Venere santa!
Bl. Non temere... (trascinandola via) Venere ti ascolterà... Io
attentare al tuo onore!... (escono continuando la vecchia a
lamentarsi e Blèpo a sermoneggiarla).
SCENA VI.
Mènecle solo.
SCENA VII.
SCENA VIII.
Mènecle solo.
Cròbilo solo.
SCENA X.
Cròbilo e Aglae.
SCENA XI.
SCENA XII.
Aglae sola.
(Seguendo Cròbilo dello sguardo) Imparerai meglio un'altra volta la
missione del consolatore... (pausa; poi fattasi triste, pensierosa,
sospirando) Eppure, soltanto la povera Aglae lo sa, se il suo cuore
avrebbe oggi bisogno davvero di conforto!... Coraggio!... Fra breve
egli sarà qui a dirmi addio... Povero Elèo! (leva dallo strofio un
piccolo papiro e legge)
SCENA XIII.
Aglae ed Elèo.
SCENA XIV.
Detti e Mènecle.
Agl. No... lasciami dire... Non ti accuso... Il tempo non muterà la tua
tempra, ma muterà molte cose intorno a te... Mènecle vivrà, e glielo
auguro, buon vecchio! molti anni...
El. (melanconico) Oh... anch'io...
Agl. ... e il giorno che io sarò libera di nozze, io non sarò più una
ragazza per te. Breve è la stagion della donna — e s'ella non la
coglie — passata quella, se ne sta seduta a consultar gli auguri [212].
Le rose della giovinezza in quel dì saranno svanite, e a te, nel fior
degli anni, non resterebbe a sposar che la memoria e l'ombra di colei
che fu un tempo la bella Aglae... una brutta vecchia grinzosa... Oh,
sarebbe troppo pretendere...
Mèn. (di dietro, tentennando il capo) (Infatti...)
Agl. ... e faresti la figura di Cròbilo. Direbbero che m'hai sposata per
godere la mia dote, la eredità di Mènecle. No, no, promettimi solo
che il giorno in cui il tuo cuore sarà stanco di attendere... rimanderai
ad Aglae questo ricordo...
El. Fino a che tra i viventi mi rischiari il sole, questo ricordo starà con
me. Verrà con me nella pugna, poserà con me sotto la tenda. Oh gli
anni possono involarci la cara giovinezza, spegnere le febbri, i delirî
dei sensi, ma non ispegneranno un affetto reso puro e santo dal
sagrificio...
Mèn. (È nato per far l'oratore!...)
El. (con forza) ... prima che io rinneghi la fede di questo affetto,
possa Nettuno farmi morire come Ippolito... e casto come lui!...
Mèn. (Povero ragazzo! te ne accorgeresti!...)
Agl. (buttandosi al collo di Elèo) Oh... lasciamo questi giuramenti...
Mèn. (To'! ha più giudizio di lui!...)
Agl. Sia dell'avvenire e del cuor tuo quello che gli Dei vorranno. Io ti
ringrazio del conforto che m'hanno dato le tue parole. Esse mi
renderanno più forte in questa prova... Che se vi avessi a
soccombere... (con voce triste, infantile) dirò a Mènecle che mi
faccia un bel sepolcro tutto bianco... bianco... e tu ci verrai...
El. Oh taci! Non parlar di morire; dimmi che in te la memoria di
quest'ora non morirà... Me lo prometti?
Agl. (volgendosi all'altare domestico) Qui all'ara del Dio che ci
ascolta...
El. E mi giuri che se Mènecle...
Agl. (senza guardar Elèo, esitante, gli occhi a terra) ... il buon
vecchio Mènecle...
Mèn. (Poverina! ci ha aggiunto anche il buono!..)
Agl. (arrestandosi e riprendendo premurosa) ... che noi dobbiamo
amare, finchè vive, come fosse nostro padre, n'è vero?
El. (triste, a capo basso) Oh, sì... come un padre...
Agl. (riprendendo esitante il filo della frase) ... se il buon vecchio
Mènecle ci venisse un giorno rapito dalla Parca triste...
El. ... inesorabile!...
Agl. ... scellerata!...
Mèn. (c. s.) (Si sfogano colla Parca... meno male...)
El. ... e che io fossi vivo...
Agl. E io anche...
El. E tutti due...
Agl. E tutti due quella perdita... amara... (appoggia la voce
sull'amara, quasi volesse correggere un pensiero colpevole: Elèo
assente col gesto) ci trovasse ancor giovani... in età da marito...
(Sempre esitante, a occhi bassi, come avesse paura o rimorso
di compier la frase)
(Quadro).
CALA LA TELA.
NOTE
204.
Dopo che il tebano Pelopida ebbe persuasi i suoi compagni
di esilio all'impresa di partirsi da Atene per muovere alla
liberazione di Tebe «mandaron essi nascostamente a Tebe
ad avvertire dei loro disegni gli amici ch'eran ivi rimasti:
tra questi Carone ed Epaminonda..... Stabilitosi quindi il
giorno dell'impresa, parve bene ai profughi che l'un d'essi,
Ferenico, raccogliendo gli altri, facesse sosta in Triasio, e
che pochi de' più giovani arditamente si arrischiassero di
entrare in città: e se a questi incogliesse mai qualche
sinistro dalla parte de' nemici, gli altri tutti aver cura
dovessero de' figliuoli e de' padri loro. Il primo che si esibì
ad andarci fu Pelopida, e poi Melone e Dàmocle e
Teopompo, stretti fra loro co' vincoli d'amicizia e di fede,
ed emuli sempre della gloria e del valore. Essendo dodici
in tutto, dopo aver abbracciato quelli che restavano
addietro, e mandato innanzi un messo a Carone, si
incamminarono succintamente vestiti... ecc. ecc.»
Plutarco, in Pelopida.
205.
Cfr. nell'arringa di Lisia per la uccision di Eratostene, il
racconto del marito Eufileto: «Tornato a casa, ordinai alla
fantesca di seguirmi in piazza; e condottala ad uno de'
miei famigliari, le dissi che sapevo tutto quel che
succedeva in casa mia. A te, quindi, soggiungevo, sta lo
sceglier fra i due: o passata per le verghe esser
condannata a rigirar la mola, tra patimenti senza fine, o
confessando la verità andar illesa, e aver da me il perdono
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about books and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookgate.com