There are five forms of accessibility: • public members are available to all code; • protected members are accessible only from derived classes; • internal members are accessible only fr
Trang 1uses a for statement to write out the integer values 1 through 10.
1.7.10 The foreach statement
A foreach statement enumerates the elements of a collection, executing a statement for each element of thecollection
static void WriteList(ArrayList list) {
foreach (object o in list) Console.WriteLine(o);
}
static void Main() {
ArrayList list = new ArrayList();
for (int i = 0; i < 10; i++) list.Add(i);
WriteList(list);
}
}
uses a foreach statement to iterate over the elements of a list
1.7.11 The break statement an d the continue statement
A break statement exits the nearest enclosing switch, while, do, for, or foreach statement; a continuestarts a new iteration of the nearest enclosing while, do, for, or foreach statement
1.7.12 The return statement
A return statement returns control to the caller of the member in which the return statement appears Areturn statement with no expression can be used only in a member that does not return a value (e.g., a methodthat returns void) A return statement with an expression can only be used only in a function member thatreturns an expression
1.7.13 The throw statement
The throw statement throws an exception
1.7.14 The try statement
The try statement provides a mechanism for catching exceptions that occur during execution of a block Thetry statement furthermore provides the ability to specify a block of code that is always executed when controlleaves the try statement
1.7.15 The checked and unchec ked statements
The checked and unchecked statements are used to control the overflow checking context for arithmeticoperations and conversions involving integral types The checked statement causes all expressions to be
evaluated in a checked context, and the unchecked statement causes all expressions to be evaluated in anunchecked context
Trang 21.7.16 The lock statement
The lock statement obtains the mutual-exclusion lock for a given object, executes a statement, and then
releases the lock
Each member of a class has a form of accessibility There are five forms of accessibility:
• public members are available to all code;
• protected members are accessible only from derived classes;
• internal members are accessible only from within the same assembly;
• protected internal members are accessible only from derived classes within the same assembly;
• private members are accessible only from the class itself
1.9 Structs
The list of similarities between classes and structs is long – structs can implement interfaces, and can have thesame kinds of members as classes Structs differ from classes in several important ways, however: structs arevalue types rather than reference types, and inheritance is not supported for structs Struct values are storedeither “on the stack” or “in-line” Careful programmers can enhance performance through judicious use ofstructs
For example, the use of a struct rather than a class for a Point can make a large difference in the number ofallocations The program below creates and initializes an array of 100 points With Point implemented as aclass, the program instantiates 101 separate objects – one for the array and one each for the 100 elements
static void Main() {
Point[] points = new Point[100];
for (int i = 0; i < 100; i++) points[i] = new Point(i, i*i);
}
}
Trang 3If Point is instead implemented as a struct, as in
1.10 Interfaces
Interfaces are used to define a contract; a class or struct that implements the interface must adhere to this
contract Interfaces can contain methods, properties, indexers, and events as members
void F(int value);
string P { get; set; }
}
public delegate void EventHandler(object sender, Event e);
shows an interface that contains an indexer, an event E, a method F, and a property P
Interfaces may employ multiple inheritance In the example below, the interface IComboBox inherits from bothITextBox and IListBox
interface IComboBox: ITextBox, IListBox {}
Classes and structs can implement multiple interfaces In the example below, the class EditBox derives fromthe class Control and implements both IControl and IDataBound
Trang 4public void Paint();
public void Bind(Binder b) { }
}
In the example above, the Paint method from the IControl interface and the Bind method from
IDataBound interface are implemented using public members on the EditBox class C# provides an
alternative way of implementing these methods that allows the implementing class to avoid having these
members be public Interface members can be implemented by using a qualified name For example, the
EditBox class could instead be implemented by providing IControl.Paint and IDataBound.Bind
static void Main() {
EditBox editbox = new EditBox();
editbox.Paint(); // error: EditBox does not have a Paint method IControl control = editbox;
control.Paint(); // calls EditBox’s implementation of Paint }
An interesting and useful property of a delegate is that it does not know or care about the class of the object that
it references Any object will do; all that matters is that the method’s signature matches the delegate’s Thismakes delegates perfectly suited for "anonymous" invocation This is a powerful capability
Trang 5There are three steps in defining and using delegates: declaration, instantiation, and invocation Delegates aredeclared using delegate declaration syntax A delegate that takes no arguments and returns void can be declaredwith
delegate void SimpleDelegate();
A delegate instance can be instantiated using the new keyword, and referencing either an instance or classmethod that conforms to the signature specified by the delegate Once a delegate has been instantiated, it can becalled using method call syntax In the example
static void Main() {
SimpleDelegate d = new SimpleDelegate(F);
d();
}
}
a SimpleDelegate instance is created and then immediately invoked
Of course, there is not much point in instantiating a delegate for a method and then immediately calling via thedelegate, as it would be simpler to call the method directly Delegates show their usefulness when their
anonymity is used For example, we could define a MultiCall method that can call repeatedly call a
SimpleDelegate
void MultiCall(SimpleDelegate d, int count) {
for (int i = 0; i < count; i++)
Trang 6activities For example, the use of Color rather than int for a parameter type enables smart code editors tosuggest Color values.
1.13 Namespaces
C# programs are organized using namespaces Namespaces are used both as an “internal” organization systemfor a program, and as an “external” organization system – a way of presenting program elements that are
exposed to other programs
Earlier, we presented a “Hello, world” program We’ll now rewrite this program in two pieces: a
HelloMessage component that provides messages and a console application that displays messages
First, we’ll provide a HelloMessage class in a namespace What should we call this namespace? By
convention, developers put all of their classes in a namespace that represents their company or organization.We’ll put our class in a namespace named Microsoft.CSharp.Introduction
}
Namespaces are hierarchical, and the name Microsoft.CSharp.Introduction is actually shorthand fordefining a namespace named Microsoft that contains a namespace named CSharp that itself contains anamespace named Introduction, as in:
}
}
Next, we’ll write a console application that uses the HelloMessage class We could just use the fully qualifiedname for the class – Microsoft.CSharp.Introduction.HelloMessage – but this name is quite long andunwieldy An easier way is to use a “using” directive, which makes it possible to use all of the types in a
namespace without qualification
Trang 7using Microsoft.CSharp.Introduction;
class Hello
{
static void Main() {
HelloMessage m = new HelloMessage();
using MessageSource = Microsoft.CSharp.Introduction.HelloMessage;
class Hello
{
static void Main() {
MessageSource m = new MessageSource();
System.Console.WriteLine(m.GetMessage());
}
}
1.14 Properties
A property is a named attribute associated with an object or a class Examples of properties include the length of
a string, the size of a font, the caption of a window, the name of a customer, and so on Properties are a naturalextension of fields – both are named members with associated types, and the syntax for accessing fields andproperties is the same However, unlike fields, properties do not denote storage locations Instead, propertieshave accessors that specify the statements to execute in order to read or write their values Properties thusprovide a mechanism for associating actions with the reading and writing of an object’s attributes, and theyfurthermore permit such attributes to be computed
The success of rapid application development tools like Visual Basic can, to some extent, be attributed to theinclusion of properties as a first-class element VB developers can think of a property as being field-like, andthis allows them to focus on their own application logic rather than on the details of a component they happen to
be using On the face of it, this difference might not seem like a big deal, but modern component-orientedprograms tend to be chockfull of property reads and writes Languages with method-like usage of properties(e.g., o.SetValue(o.GetValue() + 1);) are clearly at a disadvantage compared to languages that featurefield-like usage of properties (e.g., o.Value++;)
Properties are defined in C# using property declaration syntax The first part of the syntax looks quite similar to
a field declaration The second part includes a get accessor and/or a set accessor In the example below, theButton class defines a Caption property
public class Button: Control
{
private string caption;
public string Caption {
get { return caption;
}
Trang 8set { caption = value;
Repaint();
} }
}
Properties that can be both read and written, like the Caption property, include both get and set accessors Theget accessor is called when the property’s value is read; the set accessor is called when the property’s value iswritten In a set accessor; the new value for the property is given in an implicit value parameter
Declaration of properties is relatively straightforward, but the true value of properties shows itself is in theirusage rather than in their declaration The Caption property can read and written in the same way that fieldscan be read and written:
Button b = new Button();
b.Caption = "ABC"; // set
string s = b.Caption; // get
b.Caption += "DEF”; // get & set
public class ListBox: Control
{
private string[] items;
public string this[int index] {
get { return items[index];
} set { items[index] = value;
Repaint();
} }
Trang 91.16 Events
Events permit a class to declare notifications for which clients can attach executable code in the form of eventhandlers Events are an important aspect of the design of class libraries in general, and of the system-providedclass library in particular C# provides an integrated solution for events
A class defines an event by providing an event declaration, which looks quite similar to a field or event
declaration but with an added event keyword The type of this declaration must be a delegate type In theexample below, the Button class defines a Click event of type EventHandler
public delegate void EventHandler(object sender, Event e);
public class Button: Control
{
public event EventHandler Click;
public void Reset() {
Click = null;
}
}
Inside the Button class, the Click member can be corresponds exactly to a private field of type
EventHandler However, outside the Button class, the Click member can only be used on the left hand side
of the += and -= operators This restricts client code to adding or removing an event handler In the client codeexample below, the Form1 class adds Button1_Click as an event handler for Button1’s Click event In theDisconnect method, the event handler is removed
Button Button1 = new Button();
void Button1_Click(object sender, Event e) {
Console.WriteLine("Button1 was clicked!");
}
public void Disconnect() {
Button1.Click -= new EventHandler(Button1_Click);
} }
Trang 101.17 Versioning
Versioning is an after-thought in most languages, but not in C#
“Versioning” actually has two different meanings A new version of a component is “source compatible” with aprevious version if code that depends on the previous version can, when recompiled, work with the new version
In contrast, for a “binary compatible” component, a program that depended on the old version can, withoutrecompilation, work with the new version
Most languages do not support binary compatibility at all, and many do little to facilitate source compatibility
In fact, some languages contain flaws that make it impossible, in general, to evolve a class over time withoutbreaking some client code
As an example, consider the situation of a base class author who ships a class named Base In this first version,Base contains no F method A component named Derived derives from Base, and introduces an F ThisDerived class, along with the class Base that it depends on, is released to customers, who deploy to numerousclients and servers
}
This new version of Base should be both source and binary compatible with the initial version (If it weren’tpossible to simply add a method then a base class could never evolve.) Unfortunately, the new F in Base makesthe meaning of Derived’s F is unclear Did Derived mean to override Base’s F? This seems unlikely, sincewhen Derived was compiled, Base did not even have an F! Further, if Derived’s F does override Base’s F,then does Derived’s F adhere to the contract specified by Base? This seems even more unlikely, since it ispretty darn difficult for Derived’s F to adhere to a contract that didn’t exist when it was written For example,the contract of Base’s F might require that overrides of it always call the base Derived’s F could not possiblyadhere to such a contract since it cannot call a method that does not yet exist
Trang 11In practice, will name collisions of this kind actually occur? Let’s consider the factors involved First, it isimportant to note that the authors are working completely independently – possibly in separate corporations – so
no collaboration is possible Second, there may be many derived classes If there are more derived classes, thenname collisions are more likely to occur Imagine that the base class is Form, and that all VB, VC++ and C#developers are creating derived classes – that’s a lot of derived classes Finally, name collisions are more likely
if the base class is in a specific domain, as authors of both a base class and its derived classes are likely tochoose names from this domain
C# addresses this versioning problem by requiring developers to clearly state their intent In the original codeexample, the code was clear, since Base did not even have an F Clearly, Derived’s F is intended as a newmethod rather than an override of a base method, since no base method named F exists
}
If Base adds an F and ships a new version, then the intent of a binary version of Derived is still clear –
Derived’s F is semantically unrelated, and should not be treated as an override
However, when Derived is recompiled, the meaning is unclear – the author of Derived may intend its F tooverride Base’s F, or to hide it Since the intent is unclear, the C# compiler produces a warning, and by defaultmakes Derived’s F hide Base’s F – duplicating the semantics for the case in which Derived is not
recompiled This warning alerts Derived’s author to the presence of the F method in Base If Derived’s F issemantically unrelated to Base’s F, then Derived’s author can express this intent – and, in effect, turn off thewarning – by using the new keyword in the declaration of F
}
Trang 12declarative information by defining and using attributes.
For instance, a framework might define a HelpAttribute attribute that can be placed on program elementssuch as classes and methods to provide a mapping from program elements to documentation for them Theexample
Trang 13public string Topic = null;
private string url;
public string Url {
get { return url; } }
}
defines an attribute class named HelpAttribute, or Help for short, that has one positional parameter (stringurl) and one named argument (string Topic) Positional parameters are defined by the formal parameters forpublic constructors of the attribute class; named parameters are defined by public read-write properties of theattribute class The square brackets in the example indicate the use of an attribute in defining the Help attribute
In this case, the AttributeUsage attribute indicates that any program element can be decorated with the Helpattribute
shows several uses of the attribute
Attribute information for a given program element can be retrieved at run-time by using the NET runtime’sreflection support The example
using System;
class Test
{
static void Main() {
Type type = typeof(Class1);
object[] arr = type.GetCustomAttributes(typeof(HelpAttribute));
if (arr.Length == 0) Console.WriteLine("Class1 has no Help attribute.");
else { HelpAttribute ha = (HelpAttribute) arr[0];
Console.WriteLine("Url = {0}, Topic = {1}", ha.Url, ha.Topic);
} }
}
checks to see if Class1 has a Help attribute, and writes out the associated Topic and Url values if the
attribute is present