Ñïàñèáî, ÷òî ñêà÷àëè êíèãó â áåñïëàòíîé ýëåêòðîííîé áèáëèîòåêå BooksCafe.Net
Âñå êíèãè àâòîðà
Ýòà æå êíèãà â äðóãèõ ôîðìàòàõ
Ïðèÿòíîãî ÷òåíèÿ!
- Introduction
- Part I
- Chapter 1
- Chapter 2
- Chapter 3
- Chapter 4
- Chapter 5
- Chapter 6
- Chapter 7
- Chapter 8
- Chapter 9
- Chapter 10
- Chapter 11
- Chapter 12
- Chapter 13
- Chapter 14
- Chapter 15
- Part II
- Chapter 16
- Chapter 17
- Chapter 18
- Chapter 19
- Chapter 20
- Part III
To my family and wife, Shihua, for their support and love.
For a detailed discussion of the features available in each edition, check out the following URL: http://msdn.microsoft.com/en-us/vs2008/products/cc149003.aspx.Express editions are designed for hobbyists and are available for download at no charge. This is a great way to get started with Visual Studio 2008 and is ideal for students and beginning programmers. However, if you are a professional developer, you should purchase either the Standard or Professional Edition. If you are developing Windows Mobile applications, you need the Professional Edition (or higher). If you are working in a large development environment and need to develop collaboratively with other developers on large projects, check out the Team System editions.
If you are not ready to purchase Visual Studio 2008, you can always download a 90-day trial edition of Visual Studio 2008 Professional from http://msdn.microsoft.com/en-us/vs2008/products/cc268305.aspx.Depending on the edition of Visual Studio you are using, some of the steps illustrated in this book may not appear exactly the same on your screen. However, the differences are minor, and you should not have any problem in following the steps outlines in each chapter.
Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text.
Tips, hints, tricks, and asides to the current discussion are offset and placed in italics like this.As for styles in the text:
Because many books have similar titles, you may find it easiest to search by ISBN; this book's ISBN is 978-0-470-28581-7.Once you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books.
You can read messages in the forums without joining P2P but to post your own messages, you must join.Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the web. If you would like to have new messages from a particular forum emailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing.
At the time of writing, Microsoft's implementation of the .NET Framework runs only on Windows operating systems. However, there is an open-source implementation of the .NET Framework, called "Mono," that runs on Mac and Linux.Figure 1-1 shows the relationships between the CLR, unmanaged and managed code.
Assemblies are discussed in more detail in Chapter 15.To get a better idea of a MSIL file and its content, take a look at the following example, which has two console applications — one written in C# and the other written in VB.NET.
Version | Version Number | Release Date | Versions of Visual Studio shipped |
---|---|---|---|
1.0 | 1.0.3705.0 | 2002-01-05 | Visual Studio .NET 2002 |
1.1 | 1.1.4322.573 | 2003-04-01 | Visual Studio .NET 2003 |
2.0 | 2.0.50727.42 | 2005-11-07 | Visual Studio 2005 |
3.0 | 3.0.4506.30 | 2006-11-06 | Shipped with Windows Vista |
3.5 | 3.5.21022.8 | 2007-11-19 | Visual Studio 2008 |
.NET Framework version 3.5 is dependent on .NET 2.0 and 3.0. If you have a computer with .NET 1.0, 1.1, and 2.0 installed, these three versions are completely separate from each other. When you install .NET 3.5 on a computer without the .NET Framework installed, it will first install .NET 2.0, followed by .NET 3.0, and then finally the new assemblies new in .NET 3.5.Figure 1-4 summarizes the relationships between .NET 2.0, 3.0, and 3.5.
For a detailed discussion of the features available in each edition, check out the following URL: http://msdn.microsoft.com/en-us/vs2008/products/cc149003.aspx.The Express editions are designed for hobbyists and are available for download at no charge. This is a great way to get started with Visual Studio 2008 and is ideal for students and beginning programmers. However, if you are a professional developer, you should purchase either the Standard or Professional Edition. Note that if you are developing Windows Mobile applications, you need the Professional Edition (or higher). If you are working in a large development environment and need to develop collaboratively with other developers on large projects, check out the Team System editions.
If you are not ready to purchase Visual Studio 2008, you can always download a 90-day trial edition of Visual Studio 2008 Professional from http://msdn.microsoft.com/en-us/vs2008/products/cc268305.aspx.
Remember: A solution contains one or more projects.
Missing Controls in Toolbox
Sometimes, for some unknown reasons, the controls in the Toolbox may suddenly go missing. The usual remedy is to right-click the Toolbox and select Reset Toolbox. This works most of the time. However, if that fails to work, you may need to do the following:
Navigate to C:\Documents and Settings\<user_name>\Local Settings\Application Data\Microsoft\VisualStudio\9.0.
Within this folder are some hidden files. Simply delete the following files: toolbox.tbd, toolboxIndex.tbd, toolbox_reset.tbd, and toolboxIndex_reset.tbd.
Then restart Visual Studio 2008. Your controls should now come back up!
The buttons in the Solution Explorer window are context sensitive, which means that some buttons will not be visible when certain items are selected. For instance, if you select the project name, the View Code and View Designer buttons will not be shown.To add additional items such as a Windows Form or a Class to your current project, right-click the project name in Solution Explorer, select Add (see Figure 2-24), and then choose the item you want to add from the list.
Having multiple views at the same time is useful if you have a big monitor (or multiple monitors).
Step Into and Step Over are basically the same, except when it comes to executing functions.While you are at a breakpoint stepping through the code (using either F10 or F11), you can also examine the values of variables by hovering the mouse over the object you want to examine. Figure 2-63 shows value of i when the mouse is over i.
1. Launch Visual Studio 2008.Editions of Visual Studio 2008
You can use any of the following editions of Visual Studio 2008 to create a C# program:
□ Visual C# 2008 Express Edition
□ Visual Studio 2008 Standard Edition
□ Visual Studio 2008 Professional Edition
□ Visual Studio 2008 Team Suite Edition
All the code samples and screen shots shown in this book were tested using Visual Studio 2008 Professional Edition.
Classes and objects are discussed in detail in Chapter 4.Within the Program class, you have the Main() method:
Chapters 4 and 5 provide more information about object-oriented programming.Unlike languages such as VB.NET in which a method can be either a function or a subroutine (a function returns a value; a subroutine does not), C# only supports functions. If a function does not return a result, you simply prefix the function name with the void keyword; otherwise, you indicate the return type by specifying its type.
You will find more about functions in Chapter 4.Finally, you write the statements within the Main() method:
Chapter 8 covers string arrays in depth.
The name of the variable cannot be one of the C# keywords. If you absolutely must use one of the keywords as a variable name, you need to prefix it with the @ character, as the following example shows:
int @new = 4;
Console.WriteLine(@new);
You can also generate the XML documentation file using the csc.exe compiler at the command prompt using the /doc option:In the Build tab, tick the XML Documentation File checkbox and use the default path suggested: bin\Debug\HelloWorld.XML (see Figure 3-7).
csc Program.cs /doc:HelloWorld.xml
You'll find more information about user-defined types in Chapter 4 and about anonymous types in Chapter 14.
Chapter 4 discusses structures in more detail.Point pointA, pointB;
C# Type | .NET Framework Type | Bits | Range |
---|---|---|---|
bool | System.Boolean | True or false | |
byte | System.Byte | 8 | Unsigned 8-bit integer values from 0 to 255 |
sbyte | System.SByte | 8 | Signed 8-bit integer values from -128 to 127 |
char | System.Char | 16 | 16-bit Unicode character from U+0000 to U+ffff |
decimal | System.Decimal | 128 | Signed 128-bit number from ±1.0×10-28 to ±7.9×1028 |
double | System.Double | 64 | Signed 64-bit floating point number; approximately from ±5.0×10-324 to ±1.7×10308 |
float | System.Single | 32 | Signed 32-bit floating point number; approximately from ±1.5×10-45 to ±3.4×1038 |
int | System.Int32 | 32 | Signed 32-bit integer number from -2,147,483,648 to 2,147,483,647 |
uint | System.UInt32 | 32 | Unsigned 32-bit integer number from 0 to 4,294,967,295 |
long | System.Int64 | 64 | Signed 64-bit integer number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
ulong | System.UInt64 | 64 | Unsigned 64-bit integer number from 0 to 18,446,744,073,709,551,615 |
short | System.Int16 | 16 | Signed 16-bit integer number from -32,768 to 32,767 |
ushort | System.UInt16 | 16 | Unsigned 16-bit integer number from 0 to 65,535 |
To learn the default value of a value type, use the default keyword, like this:However, C# forbids you from using a variable if you do not explicitly initialize it. The following statements, for instance, cause the compiler to complain:
object x; x = default(int);
Console.WriteLine(x); //---0---
x = default(bool);
Console.WriteLine(x); //---false---
You read this statement as "Nullable of Boolean." The <> represents a generic type and will be discussed in more detail in Chapter 9.In this case, married can take one of the three values: true, false, or null.
C# supports two predefined reference types — object and string — which are described in the following table.Value Types versus Reference Types
For any discussion about value types and reference types, it is important to understand how the .NET Framework manages the data in memory.
Basically, the memory is divided into two parts — the stack and the heap. The stack is a data structure used to store value-type variables. When you create an int variable, the value is stored on the stack. In addition, any call you make to a function (method) is added to the top of the stack and removed when the function returns.
In contrast, the heap is used to store reference-type variables. When you create an instance of a class, the object is allocated on the heap and its address is returned and stored in a variable located on the stack.
Memory allocation and deallocation on the stack is much faster than on the heap, so if the size of the data to be stored is small, it's better to use a value- type variable than reference-type variable. Conversely, if the size of data is large, it is better to use a reference-type variable.
C# Type | .NET Framework Type | Descriptions |
---|---|---|
object | System.Object | Root type from which all types in the CTS (Common Type System) derive |
string | System.String | Unicode character string |
Implicit-typing is very useful when using LINQ queries. Chapter 14 discusses LINQ in more detail.
Converting a value from a smaller range to a bigger range is known as widening.The following table shows the implicit conversion between the different built-in types supported by C#.
Convert from (type) | To (type) |
---|---|
sbyte | short, int, long, float, double, or decimal |
byte | short, ushort, int, uint, long, ulong, float, double, or decimal |
short | int, long, float, double, or decimal |
ushort | int, uint, long, ulong, float, double, or decimal |
int | long, float, double, or decimal |
uint | long, ulong, float, double, or decimal |
long | float, double, or decimal |
char | ushort, int, uint, long, ulong, float, double, or decimal |
float | double |
ulong | float, double, or decimal |
Converting a value from a bigger range to a smaller range is known as narrowing. Narrowing can result in a loss of data, so be careful when performing a narrowing operation.The preceding statement could be made valid when you perform a type casting operation by prefixing the variable that you want to assign with the target type in parentheses:
By default, Visual Studio 2008 checks statements involving constant assignments for overflow during compile time. However, this checking is not enforced for statements whose values cannot be determined at runtime.To ensure that an exception is thrown during runtime when an overflow occurs, you can use the checked keyword, which is used to explicitly enable overflow-checking for integral-type arithmetic operations and conversions:
int num = 40000;
short sNum;
sNum =(short) num; //--- -25536; no exception is raised---
Remember to wrap the Boolean expression in a pair of parentheses when using the if statement.If you have multiple statements to execute after an if-else expression, enclose them in {}, like this:
?: is also known as the ternary operator.The conditional operator has the following format:
Operator | Description |
---|---|
== | Equal |
!= | Not equal |
> | Greater than |
>= | Greater than or equal to |
< | Lesser than |
<= | Lesser than or equal to |
Operator | Description |
---|---|
&& | And |
|| | Or |
! | Not |
Operand A | Operand B | Result |
---|---|---|
false | false | false |
false | true | true |
true | false | true |
true | true | true |
Operand A | Operand B | Result |
---|---|---|
false | false | false |
false | true | false |
true | false | false |
true | true | true |
Operand A | Result |
---|---|
false | true |
true | false |
Operator | Description |
---|---|
+ | Addition |
- | Subtraction |
/ | Division |
* | Multiplication |
% | Modulus |
Category | Operators |
---|---|
Primary | x.y f(x) a[x] x++ x-- new typeof checked unchecked |
Unary | + - ! ~ ++x --x (T)x |
Multiplicative | * / % |
Additive | + - |
Shift | << >> |
Relational and type testing | < > <= >> is as |
Equality | == != |
Logical AND | & |
Logical XOR | ^ |
Logical OR | | |
Conditional AND | && |
Conditional OR | || |
Conditional | ?: |
Assignment | = *= /= %= += -= <<= >>= &= ^= | = |
DEBUG is a common symbol that developers use to indicate debugging statements, which is why most books use it in examples. However, you can define any symbol you want using the #define preprocessor directive.Before compilation, the preprocessor will evaluate the #if preprocessor directive to see if the DEBUG symbol has been defined. If it has, the statement(s) wrapped within the #if and #endif preprocessor directives will be included for compilation. If the DEBUG symbol has not been defined, the statement — the statement(s) wrapped within the #if and #endif preprocessor — will be omitted from the compilation.
The line numbers are for illustration purposes and are not part of the program.The four highlighted lines are numbered 13, 14, 20, and 23. When you build the program in Visual Studio 2008, the lines reported are 25, 26, 20, and 45 (see Figure 3-18).
Interestingly, you can replace the #line hidden preprocessor directive with #line 16707566 (0xFeeFee) and it will still work correctly.
Uses for Partial Classes
There are a couple of very good reasons to use partial classes. First, using partial classes enables the programmers on your team to work on different parts of a class without needing to share the same physical file. While this is useful for projects that involve big class files, be wary: a huge class file may signal a design fault, and refactoring may be required.
Second, and most compelling, you can use partial classes to separate your application business logic from the designer-generated code. For example, the code generated by Visual Studio 2008 for a Windows Form is kept separate from your business logic. This prevents developers from messing with the code that is used for the user interface. At the same time, it prevents you from losing your changes to the designer-generated code when you change the user interface.
Chapter 3 discusses the new C# 3.0 keyword var.Here, book1 is an object with 4 properties: ISBN, Title, Author, and Publisher (see Figure 4-1).
C# anonymous types are immutable, which means all the properties are read-only — their values cannot be changed once they are initialized.You can use variable names when assigning values to properties in an anonymous type; for example:
Type | Description |
---|---|
Data | Members that store the data needed by your object so that they can be used by functions to perform their work. For example, you can store a person's name using the FirstName and LastName members. |
Function | Code blocks within a class. Function members allow the class to perform its work. For example, a function contained within a class (such as the Contact class) can validate the email of a person (stored in the Email member) to see if it is a valid email address. |
By convention, you can denote a private variable by beginning its name with the underscore (_) character. This is recommended, but not mandatory.For example, you can access the FirstName data member through an instance of the Contact class:
C# has four access modifiers — private, public, protected, and internal.The last two are discussed with inheritance in the next chapter.If a data member is declared without the public keyword, its scope (or access) is private by default. So, _Email can also be declared like this:
Because C# functions can only return single values, passing arguments by reference is useful when you need a method to return multiple values.In this case, the values of variables passed into this function will be modified, as the following example illustrates:
A partial method must be declared within a partial class or partial struct.Partial methods must adhere to the following rules:
If you do not define a default constructor in your class, an implicit default constructor is automatically created by the compiler.You can have as many constructors as you need to, as long as each constructor's signature (parameters) is different. Let's now add two more constructors to the Contact class:
Chapter 5 discusses the concept of interfaces in more detail.The following shows the Contact class implementing the IDisposable class and implementing the Dispose() method:
The Using Statement
C# provides a convenient syntax for automatically calling the Dispose() method, using the using keyword. In the following example, the conn object is only valid within the using block and will be disposed automatically after the execution of the block.
using System.Data.SqlClient;
...
using (SqlConnection conn = new SqlConnection()) {
conn.ConnectionString = "...";
//...
}
Using the using keyword is a good way for you to ensure that resources (especially COM objects and unmanaged code, which will not be unloaded automatically by the garbage collector in the CLR) are properly disposed of once they are no longer needed.
If two objects have reference equality, they also have value equality, but the reverse is not necessarily true.
Notice that the Equals() methods essentially performs the following to determine if two objects are equal in value:The as Keyword
In the Equals(object obj) method you saw the use of the as keyword:
Contact c = obj as Contact;
The as operator performs conversions between compatible types. In this case, it tries to cast the obj object into a Contact object. The as keyword is discussed in detail in Chapter 5.
Remember, a struct cannot have a default constructor.Note that the compiler will complain with the message "Backing field for automatically implemented property 'Coordinate.latitude' must be fully assigned before control is returned to the caller" when you try to compile this application. This restriction applies only to structs (classes won't have this problem). To resolve this, you need to call the default constructor of the struct, like this:
Memory Allocation
When you use the new keyword to create an instance of a class, the object will be allocated on the heap. When using structs, the struct object is created on the stack instead. Because of this, using structs yields better performance gains. Also, when passing a struct to a method, note that it is passed by value instead of passed by reference.
In general, use classes when dealing with large collections of data. When you have smaller sets of data to deal with, using structs is more efficient.
This chapter explains how to define an interface and how to implement the interface using a class.Differences between an Interface and an Abstract Base Class
Conceptually, an abstract class is similar to an interface; however, they do have some subtle differences:
□ An abstract class can contain a mixture of concrete methods (implemented) and abstract methods (an abstract class needs at least one abstract method); an interface does not contain any method implementations.
□ An abstract class can contain constructors and destructors; an interface does not.
□ A class can implement multiple interfaces, but it can inherit from only one abstract class.
Interface Naming Convention
By convention, begin the name of an interface with a capital I (such as IPerson, IManager, IEmployee, and so on) so that it is clear that you are dealing with an interface.
Notice that I'm using the new automatic properties feature (discussed in Chapter 4) in C# 3.0 to implement the Name and DateofBirthproperties. That's why the implementation looks the same as the declaration in the interface.As explained, all implemented members must have the public access modifiers.
An abstract method can only be defined in an abstract class.The base keyword refers to the parent class of a derived class, not the root class. Consider the following example where you have three classes — Class3 inherits from Class2, which in turn inherits from Class1:
See the "Overloading Methods" section later in this chapter.
In C#, you use the new keyword to hide methods in the base class by signature. C# does not support hiding methods by name as is possible in VB.NET by using the Shadows keyword.The following table summarizes the different keywords used for inheritance.
Modifier | Description |
---|---|
new | Hides an inherited method with the same signature. |
static | A member that belongs to the type itself and not to a specific object. |
virtual | A method that can be overridden by a derived class. |
abstract | Provides the signature of a method/class but does not contain any implementation. |
override | Overrides an inherited virtual or abstract method. |
sealed | A method that cannot be overridden by derived classes; a class that cannot be inherited by other classes. |
extern | An "extern" method is one in which the implementation is provided elsewhere and is most commonly used to provide definitions for methods invoked using .NET interop. |
Remember that if a base class contains constructors, one of them must be a default constructor.
You not need to implement the IShape class because you can't provide any meaningful implementation of the Area() and Perimeter() methods here.Because the IRectangle interface inherits from both the ISquare and IShape interfaces and the ISquare interface has already been implemented (by the Square class), you can simply inherit from the Square class and implement the IRectangle interface, like this:
If you implement the IRectangle interface directly (without inheriting from the Square class, you need to provide the implementation of the length property as well as the methods Perimeter() and Area().You need only provide the implementation for the width property here. The implementation for the Area() and Perimeter() methods is inherited from the Square class.
You cannot use the public access modifier on the explicit interface methods' implementation.To invoke these implementations of the LogError() method, use the following statements:
Abstract Classes versus Interfaces
An abstract class defines the members and optionally provides the implementations of each member. Members that are not implemented in the abstract class must be implemented by classes that inherit from it.
An interface, on the other hand, defines the signatures of members but does not provide any implementation. All the implementations must be provided by classes that implement it.
So which one should you use? There are no hard-and-fast rules, but here are a couple of points to note:
□ You can add additional members to classes as and when needed. In contrast, once an interface is defined (and implemented by classes), adding additional members will break existing code.
□ Classes support only single-inheritance but can implement multiple interfaces. So if you need to define multiple contracts (rules) for a type, it is always better to use an interface.
Chapter 10 discusses more about threading.
Lambda expressions are discussed in more detail in Chapter 14.
The next section explains how you can create another class that derives from this EventArgs base class to pass back information to an event handler.Define the constructor for the AlarmClock class so that the Timer object (t) will fire its Elapsed event every 100 milliseconds. In addition, wire the Elapsed event with an event handler. The event handler will check the current time against the time set by the user of the class. If the time equals or exceeds the user's set time, the event handler calls the onTimesUp() method that you defined in the previous step:
A string cannot be a value type because of its unfixed size. All values types (int, double, and so on) have fixed size.A string is essentially a collection of Unicode characters. The following statements show how you enumerate a string as a collection of char and print out the individual characters to the console:
You learn more about formatting options in the section "String Formatting" later in this chapter.Besides the \n and \t escape characters, C# also supports the \r escape character. \r is the carriage return character. Consider the following example:
By default, when you use the \n to insert a new line, the cursor is automatically returned to the beginning of the line. However, some legacy applications still require you to insert newline and carriage return characters in strings.The following table summarizes the different escape sequences you have seen in this section:
Sequence | Purpose |
---|---|
\n | New line |
\r | Carriage return |
\r\n | Carriage return; New line |
\" | Quotation marks |
\\ | Backslash character |
\t | Tab |
Escape Code for Unicode
C# supports the use of escape code to represent Unicode characters. The four-digit escape code format is: \udddd. For example, the following statement prints out the £ symbol:
string symbol = "\u00A3";
Console.WriteLine(symbol);
For more information on Unicode, check out http://unicode.org/Public/UNIDATA/NamesList.txt.
You can find out about all of the String class methods at www.msdn.com.
Method | Description |
---|---|
Compare(String, String) | Compares two specified String objects. |
Compare(String, String, Boolean) | Compares two specified String objects, ignoring or respecting their case. |
Compare(String, String, StringComparison) | Compares two specified String objects. Also specifies whether the comparison uses the current or invariant culture, honors or respects case, and uses word or ordinal sort rules. |
Compare(String, String, Boolean, CultureInfo) | Compares two specified String objects, ignoring or respecting their case, and using culture-specific information for the comparison. |
Compare(String, Int32, String, Int32, Int32) | Compares substrings of two specified String objects. |
Compare(String, Int32, String, Int32, Int32, Boolean) | Compares substrings of two specified String objects, ignoring or respecting their case. |
Compare(String, Int32, String, Int32, Int32, StringComparison) | Compares substrings of two specified String objects. |
Compare(String, Int32, String, Int32, Int32, Boolean, CultureInfo) | Compares substrings of two specified String objects, ignoring or respecting their case, and using culture-specific information for the comparison. |
The String.Join() static method is useful when you need to join a series of strings stored in a string array. The following example shows the strings in a string array joined using the Join() method:Strings Are Immutable
In .NET, all string objects are immutable. This means that once a string variable is initialized, its value cannot be changed. And when you modify the value of a string, a new copy of the string is created and the old copy is discarded. Hence, all methods that process strings return a copy of the modified string — the original string remains intact.
For example, the Insert() instance method inserts a string into the current string and returns the modified string:
str1 = str1.Insert(10, "modified ");
In this statement, you have to assign the returned result to the original string to ensure that the new string is modified.
For a detailed list of format specifiers you can use for formatting strings, please refer to the MSDN documentation under the topics "Standard Numeric Format Strings" and "Custom Numeric Format Strings. "You can also print out specific strings based on the value of a number. Consider the following example:
One important application of the StringBuilder class is its use in .NET interop with native C/C++ APIs that take string arguments and modify strings. One example of this is the Windows API function GetWindowText(). This function has a second argument that takes a TCHAR* parameter. To use this function from .NET code, you would need to pass a StringBuilder object as this argument.Consider the following example, where you concatenate all the numbers from 0 to 9999:
Method | Description |
---|---|
Append | Appends the string representation of a specified object to the end of this instance. |
AppendFormat | Appends a formatted string, which contains zero or more format specifiers, to this instance. Each format specification is replaced by the string representation of a corresponding object argument. |
AppendLine | Appends the default line terminator, or a copy of a specified string and the default line terminator, to the end of this instance. |
CopyTo | Copies the characters from a specified segment of this instance to a specified segment of a destination Char array. |
Insert | Inserts the string representation of a specified object into this instance at a specified character position. |
Remove | Removes the specified range of characters from this instance. |
Replace | Replaces all occurrences of a specified character or string in this instance with another specified character or string. |
ToString | Converts the value of a StringBuilder to a String. |
Operator | Description |
---|---|
. | Match any one character |
[ ] | Match any one character listed between the brackets |
[^ ] | Match any one character not listed between the brackets |
? | Match any character one time, if it exists |
* | Match declared element multiple times, if it exists |
+ | Match declared element one or more times |
{n} | Match declared element exactly n times |
{n,} | Match declared element at least n times |
{n,N} | Match declared element at least n times, but not more than N times |
^ | Match at the beginning of a line |
$ | Match at the end of a line |
\< | Match at the beginning of a word |
\> | Match at the end of a word |
\b | Match at the beginning or end of a word |
\B | Match in the middle of a word |
\d | Shorthand for digits (0-9) |
\w | Shorthand for word characters (letters and digits) |
\s | Shorthand for whitespace |
Pattern | Description |
---|---|
[0-9] | Digits |
[A-Fa-f0-9] | Hexadecimal digits |
[A-Za-z0-9] | Alphanumeric characters |
[A-Za-z] | Alphabetic characters |
[a-z] | Lowercase letters |
[A-Z] | Uppercase letters |
[ \t] | Space and tab |
[\x00-\x1F\x7F] | Control characters |
[\x21-\x7E] | Visible characters |
[\x20-\x7E] | Visible characters and spaces |
[!"#$%&'()*+,-./:;<=>?@[\\\]_`{|}~] | Punctuation characters |
[ \t\r\n\v\f] | Whitespace characters |
\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-,]\w+)* | Email address |
http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)? | Internet URL |
((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4} | U.S. phone number |
\d{3}-\d{2}-\d{4} | U.S. Social Security number |
\d{5}(-\d{4})? | U.S. ZIP code |
There are many different regular expressions that you can use to validate an email address. However, there is no perfect regular expression to validate all email addresses. For more information on validating email addresses using regular expressions, check out the following web sites: http://regular-expressions.info/email.html and http://fightingforalostcause.net/misc/2006/compare-email-regex.php.
You can use any variable name you want to represent the generic parameter. T is chosen as the generic parameter for illustration purposes.If you want the MyStack class to manipulate items of type int, specify that during the instantiation stage (int is called the type argument):
A constructed type is a generic type with at least one type argument.In Figure 9-1 IntelliSense shows that the Push() method now accepts arguments of type int.
The base class constraint must always be specified first, before specifying the interface.Assuming that you have the following Manager class deriving from the Employee class:
Class | Description |
---|---|
Comparer<(Of <(T>)>) | Provides a base class for implementations of the IComparer<(Of <(T>)>) generic interface. |
Dictionary<(Of <(TKey, TValue>)>) | Represents a collection of keys and values. |
Dictionary<(Of <(TKey, TValue>)<)..::.KeyCollection | Represents the collection of keys in a Dictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. |
Dictionary<(Of <(TKey, TValue>)>)..::.ValueCollection | Represents the collection of values in a Dictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. |
EqualityComparer<(Of <(T>)>) | Provides a base class for implementations of the IEqualityComparer<(Of <(T>)>) generic interface. |
HashSet<(Of <(T>)>) | Represents a set of values. |
KeyedByTypeCollection<(Of <(TItem>)>) | Provides a collection whose items are types that serve as keys. |
KeyNotFoundException | The exception that is thrown when the key specified for accessing an element in a collection does not match any key in the collection. |
LinkedList<(Of <(T>)>) | Represents a doubly linked list. |
LinkedListNode<(Of <(T>)>) | Represents a node in a LinkedList<(Of <(T>)>). This class cannot be inherited. |
List<(Of <(T>)>) | Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists. |
Queue<(Of <(T<)>) | Represents a first-in, first-out collection of objects. |
SortedDictionary<(Of <(TKey, TValue>)>) | Represents a collection of key/value pairs that are sorted on the key. |
SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection | Represents the collection of keys in a SortedDictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. |
SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection | Represents the collection of values in a SortedDictionary<(Of <(TKey, TValue>)>). This class cannot be inherited. |
SortedList<(Of <(TKey, TValue>)>) | Represents a collection of key/value pairs that are sorted by key based on the associated IComparer<(Of <(T>)>) implementation. |
Stack<(Of <(T>)>) | Represents a variable size last-in, first-out (LIFO) collection of instances of the same arbitrary type. |
SynchronizedCollection<(Of <(T>)>) | Provides a thread-safe collection that contains objects of a type specified by the generic parameter as elements. |
SynchronizedKeyedCollection<(Of <(K, T>)>) | Provides a thread-safe collection that contains objects of a type specified by a generic parameter and that are grouped by keys. |
SynchronizedReadOnlyCollection <(Of <(T>)>) | Provides a thread-safe, read-only collection that contains objects of a type specified by the generic parameter as elements. |
Structure | Description |
---|---|
Dictionary<(Of <(TKey, TValue>)>)..::.Enumerator | Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>) |
Dictionary<(Of <(TKey, TValue>)>)..::. KeyCollection..::.Enumerator | Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>)..::.KeyCollection |
Dictionary<(Of <(TKey, TValue>)>)..::. ValueCollection..::.Enumerator | Enumerates the elements of a Dictionary<(Of <(TKey, TValue>)>)..::.ValueCollection |
HashSet<(Of <(T>)>)..::.Enumerator | Enumerates the elements of a HashSet<(Of <(T>)>) object |
KeyValuePair<(Of <(TKey, TValue>)>) | Defines a key/value pair that can be set or retrieved |
LinkedList<(Of <(T>)>)..::.Enumerator | Enumerates the elements of a LinkedList<(Of <(T>)>) |
List<(Of <(T>)>)..::.Enumerator | Enumerates the elements of a List<(Of <(T>)>) |
Queue<(Of <(T>)>)..::.Enumerator | Enumerates the elements of a Queue<(Of <(T>)>) |
SortedDictionary<(Of <(TKey, TValue>)>)..::.Enumerator | Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>) |
SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection..::.Enumerator | Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>)..::.KeyCollection |
SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection..::. Enumerator | Enumerates the elements of a SortedDictionary<(Of <(TKey, TValue>)>)..::.ValueCollection |
Stack(<Of <(T>)>)..::.Enumerator | Enumerates the elements of a Stack<(Of <(T>)>) |
Interface | Description |
---|---|
ICollection<(Of <(T>)>) | Defines methods to manipulate generic collections |
IComparer<(Of <(T>)>) | Defines a method that a type implements to compare two objects |
IDictionary<(Of <(TKey, TValue>)>) | Represents a generic collection of key/value pairs |
IEnumerable<(Of <(T>)>) | Exposes the enumerator, which supports a simple iteration over a collection of a specified type |
IEnumerator<(Of <(T>)>) | Supports a simple iteration over a generic collection |
IEqualityComparer<(Of <(T>)>) | Defines methods to support the comparison of objects for equality |
Ilist<(Of <(T>)>) | Represents a collection of objects that can be individually accessed by index |
System.Collection | System.Collection.Generic |
---|---|
Comparer | Comparer<T> |
HashTable | Dictionary<K,T> |
— | LinkedList<T> |
ArrayList | List<T> |
Queue | Queue<T> |
SortedList | SortedDictionary<K,T> |
Stack | Stack<T> |
ICollection | ICollection<T> |
System.IComparable | IComparable<T> |
IDictionary | IDictionary<K,T> |
IEnumerable | IEnumerable<T> |
IEnumerator | IEnumerator<T> |
IList | IList<T> |
The Stack<T>, Queue<T>, and Dictionary<K,T> generic classes are discussed in more detail in Chapter 13, "Collections."
Member | Description |
---|---|
AddAfter() | Adds a new node after an existing node |
AddBefore() | Adds a new node before an existing node |
First | Gets the first node |
Last | Gets the last node |
Property | Description |
---|---|
Next | Gets the next node |
Previous | Gets the previous node |
Value | Gets the value contained in the node |
Generic Class | Description |
---|---|
Collection<T> | Provides the base class for a generic collection. |
KeyedCollection<TKey, TItem> | Provides the abstract base class for a collection whose keys are embedded in the values. |
ObservableCollection<T> | Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. |
ReadOnlyCollection<T> | Provides the base class for a generic read-only collection. |
ReadOnlyObservableCollection<T> | Represents a read-only ObservableCollection<T>. |
The List<T> generic class is discussed in details in Chapter 13.The following code example shows how to use the generic Collection<T> class:
As a rule of thumb, use the generic Collection<T> class (because it is more extensible) as a return type from a public method, and use the generic List<T> class for internal implementation.
A thread is a sequential flow of execution within a program. A program can consist of multiple threads of execution, each capable of independent execution.This chapter explains how to write multithreaded applications using the Thread class in the .NET Framework. It shows you how to:
Every application contains one main thread of execution. A multithreaded application contains two or more threads of execution.In C#, you can create a new thread of execution by using the Thread class found in the System.Threading namespace. The Thread class creates and controls a thread. The constructor of the Thread class takes in a ThreadStart delegate, which wraps the function that you want to run as a separate thread. The following code shows to use the Thread class to run the DoSomething() function as a separate thread:
Import the System.Threading namespace when using the Thread class.class Program {
In general, it is best to avoid using a public object for locking purposes. This prevents situations in which threads are all waiting for a public object, which may itself be locked by some other code.To delineate a block of code to lock, enclose the statements with the lock statement:
Control | Name | Text |
---|---|---|
Label | Number | |
Label | lblResult | label2 |
Label | Progress | |
TextBox | txtNum | |
Button | btnStart | Start |
Button | btnCancel | Cancel |
ProgressBar | ProgressBar1 |
The DoWork event handler runs on a separate thread from the UI. Be sure not to manipulate any Windows Forms controls created on the UI thread from this method.The SumNumbers() function basically sums up all the numbers from 0 to the number specified:
Remember to import the System.IO namespace when using the various classes in the System.IO namespace.
Method | Description |
---|---|
Create | Creates a directory. |
CreateSubdirectory | Creates a subdirectory. |
Delete | Deletes a directory. |
GetDirectories | Gets the subdirectories of the current directory. |
GetFiles | Gets the file list from a directory. |
Properties | Description |
---|---|
Exists | Indicates if a directory exists. |
Parent | Gets the parent of the current directory. |
FullName | Gets the full path name of the directory. |
CreationTime | Gets or sets the creation time of current directory. |
Refer to the MSDN documentation for a full list of methods and properties.To see how to use the DirectoryInfo class, consider the following example:
Method | Description |
---|---|
CreateDirectory | Creates a subdirectory. |
Delete | Deletes a specified directory. |
Exists | Indicates if a specified path exists. |
GetCurrentDirectory | Gets the current working directory. |
GetDirectories | Gets the subdirectories of the specified path. |
GetFiles | Gets the file list from a specified directory. |
SetCurrentDirectory | Sets the current working directory. |
Refer to the MSDN documentation for a full list of methods and properties.Here's the previous program using the DirectoryInfo class rewritten to use the Directory class:
In general, if you are performing a lot of operations with directories, use the DirectoryInfo class. Once it is instantiated, the object has detailed information about the directory you are currently working on. In contrast, the Directory class is much simpler and is suitable if you are occasionally dealing with directories.
You'll see more about streams in the "The Stream Class" section later in this chapter.The following code snippet uses the StreamReader class to read lines from a text file:
The Stream class is defined in the System.IO namespace. Remember to import that namespace when using the class.The following code copies the content of one binary file and writes it into another using the Stream class:
While the OpenRead() and OpenWrite() methods return a FileStream object, you can actually assign the returning type to a Stream object because the FileStream object inherits from the Stream object.To copy the content of one file into another, you use the Read() method from the Stream class and read the content from the file into an byte array. Read() returns the number of bytes read from the stream (in this case the file) and returns 0 if there are no more bytes to read. The Write() method of the Stream class writes the data stored in the byte array into the stream (which in this case is another file). Finally, you close both the Stream objects.
For binary serialization, you need to import the System.Runtime.Serialization.Formatters.Binary namespace.The Serialize() function takes in a single parameter (the BookMark object to serialize) and returns a MemoryStream object representing the serialized BookMark object. You use the BinaryFormatter class from the System.Runtime.Serialization.Formatters.Binary namespace to serialize an object. One side effect of this function is that it also serializes the BookMark object to file, using the FileStream class.
The various classes are deliberately designed to illustrate the various aspects of XML serialization. They may not adhere to the best practices for defining classes.Here are the specifics for the classes:
For XML serialization, you need to import the System.Xml.Serialization namespace.In the XMLSerialize() function, you first create a new StreamWriter object so that you can save the serialized XML string to a file. The Serialize() method from the XMLSerializer class serializes the Member object into an XML string, which is then written to file by using the StreamWriter class.
Remember to import the System.Xml namespace for the XmlReader class.To test the XMLDeserialize() function, call it directly after an object has been serialized, like this:
Property | Description |
---|---|
Data | Gets a collection of key/value pairs that provide additional user-defined information about the exception. |
HelpLink | Gets or sets a link to the help file associated with this exception. |
HResult | Gets or sets HRESULT, a coded numerical value that is assigned to a specific exception. |
InnerException | Gets the Exception instance that caused the current exception. |
Message | Gets a message that describes the current exception. |
Source | Gets or sets the name of the application or the object that causes the error. |
StackTrace | Gets a string representation of the frames on the call stack at the time the current exception was thrown. |
TargetSite | Gets the method that throws the current exception. |
You can use the ToString() method of the Exception class to retrieve more details about the exception, such as the description of the exception as well as the stack trace.However, there are cases where you would like to print your own custom error messages for the different types of exceptions. Using the preceding code, you would not be able to do that — you would need a much finer way to catch the different types of possible exceptions.
Array variables are actually objects. In this example, num, sentences, and values are objects of type System.Array.These statements simply declare the three variables as arrays; the variables are not initialized yet, and at this stage you do not know how many elements are contained within each array.
To learn the default value of a value type, use the default keyword, like this:To initialize the array to some value other than the default, you use an initialization list. The number of elements it includes must match the array's rank specifier. Here's an example:
object x;
x = default(int); //---0---
x = default(char); //---0 '\0'---
x = default(bool); //---false---
For more information on the var keyword, see Chapter 3.In C#, arrays all derive from the abstract base class Array (in the System namespace) and have access to all the properties and methods contained in that. In Figure 13-1 IntelliSense shows some of the properties and methods exposed by the num array.
The Point class represents an ordered pair of integer x- and y-coordinates that defines a point in a two-dimensional plane.You can use the array initializer to initialize the individual array within the lines array, like this:
A params parameter must always be the last parameter defined in a method declaration.
Interface | Description |
---|---|
IEnumerable<T> and IEnumerator<A> | Enable you to loop through the elements in a collection. |
ICollection<T> | Contains items in a collection and provides the functionality to copy elements to an array. Inherits from IEnumerable<T>. |
IComparer<T> and IComparable<T> | Enable you to compare objects in a collection. |
IList<T> | Inherits from ICollection and provides functionality to allow members to be accessed by index. |
IDictionary<K,V> | Similar to IList<T>, but members are accessed by key value rather than index. |
If you try to sort an ArrayList object containing elements of different types, you are likely to run into an exception because the compiler may not be able to compare the values of two different types.
Use the generic versions because they are type safe.In .NET, all classes that enumerate objects must implement the IEnumerable (or the generic IEnumerable<T>) interface. The objects enumerated must implement the IEnumerator (or the generic IEnumerable<T>) interface, which has the following members:
All the discussions from this point onward use the generic versions of the IEnumerable and IEnumerator interfaces because they are type-safe.To understand how the IEnumerable<T> and IEnumerator<T> interfaces work, modify SpamPhraseList class to implement the IEnumerable<T> interface:
Value | Meaning |
---|---|
Less than zero | The current instance is less than obj. |
Zero | The current instance is equal to obj. |
Greater than zero | The current instance is greater than obj. |
LINQ to Entities is beyond the scope of this book. It was slated to be released later in 2008 and is not part of Visual Studio 2008.So how does your application view the LINQ-enabled data sources?
Operator Type | Operator Name |
---|---|
Aggregation | Aggregate, Average, Count, LongCount, Max, Min, Sum |
Conversion | Cast, OfType, ToArray, ToDictionary, ToList, ToLookup, ToSequence |
Element | DefaultIfEmpty, ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault |
Equality | EqualAll |
Generation | Empty, Range, Repeat |
Grouping | GroupBy |
Joining | GroupJoin, Join |
Ordering | OrderBy, ThenBy, OrderByDescending, ThenByDescending, Reverse |
Partitioning | Skip, SkipWhile, Take, TakeWhile |
Quantifiers | All, Any, Contains |
Restriction | Where |
Selection | Select, SelectMany |
Set | Concat, Distinct, Except, Intersect, Union |
Deferred execution works regardless of whether you are using the query or method syntax.
Aggregate functions are discussed in more detail later in this chapter.Following is an example that uses the Count() aggregate function. The program selects all the odd numbers from an array and then counts the total number of odd numbers. Each number is then multiplied by two (which makes them all become even numbers).
using System;Preparing the Sample Database
Because SQL Server 2005 Express does not come with any sample databases, you need to install the pubs database used in this section yourself.
You can install the pubs and Northwind databases by downloading the installation scripts at http://microsoft.com/downloads. Search for: "Northwind and pubs Sample Databases for SQL Server 2000."
Once the scripts are installed on your system, go to the Visual Studio 2008 Command Prompt (Start→Programs→Microsoft Visual Studio 2008→Visual Studio Tools→Visual Studio 2008 Command Prompt) and change to the directory containing your installation scripts. Type in the following to install the two databases:
C:\SQL Server 2000 Sample Databases>sqlcmd -S .\SQLEXPRESS -i instpubs.sql
C:\SQL Server 2000 Sample Databases>sqlcmd -S .\SQLEXPRESS -i instnwnd.sql
To make use of LINQ to DataSet, ensure that you have a reference to System.Data.DataSetExtensions.dll in your project.To display the result, you can either bind the result to a DataGridView control using the AsDataView() method:
Aggregate function | Description |
---|---|
Aggregate | Performs a custom aggregation operation on the values of a collection. |
Average | Calculates the average value of a collection of values. |
Count | Counts the elements in a collection, optionally only those elements that satisfy a predicate function. |
LongCount | Counts the elements in a large collection, optionally only those elements that satisfy a predicate function. |
Max | Determines the maximum value in a collection. |
Min | Determines the minimum value in a collection. |
Sum | Calculates the sum of the values in a collection. |
To use the LINQ to XML, you must add a reference to the System.Xml.Linq.dll in your project and also import the System.Xml.Linq namespace.
The indentation gives you an overall visualization of the document structure.To save the XML document to file, use the Save() method:
The Single() method returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.Modify the field you want to change:
The First() method returns the first element of a sequence.If you have multiple rows to delete, you need to delete each row individually, like this:
Part | Description |
---|---|
Assembly metadata | Describes the assembly and its content |
Type metadata | Defines all the types and methods exported from the assembly |
IL code | Contains the MSIL code compiled by the compiler |
Resources | Contains icons, images, text strings, as well as other resources used by your application |
When you add a reference to one of the classes in the .NET class library, the Copy Local property for the added assembly will be set to False. That's because the .NET assembly is in the Global Assembly Cache (GAC), and all computers with the .NET Framework installed have the GAC. The GAC is discussed later in this chapter.Switch to the code-behind of the default Form1 and code the following statements:
Because the MathUtil.dll assembly is not digitally signed, a hacker could replace this assembly with one that contains malicious code, and the client of this assembly (which is the WindowsApp-Util application in this case) would not know that the assembly has been tampered with. Later in this chapter, you will see how to give the assembly a unique identity using a strong name.
To summarize, this example shows that:Namespace Alias
There are times when you want to specify the fully qualified name of a class so that your code is easier to understand. For example, you usually import the namespace of a class and use the class like this:
using CoolLabs.net;
//...
Class5 c5 = Class5();
c5.DoSomething();
However, you might want to use the fully qualified name for Class5 to make it clear that Class5 belongs to the CoolLabs.net namespace. To do so, you can rewrite your code like this:
CoolLabs.net.Class5 c5 = new CoolLabs.net.Class5();
c5.DoSomething();
But the CoolLabs.net namespace is quite lengthy and may make your code look long and unwieldy. To simplify the coding, you can give an alias to the namespace, like this:
using cl = CoolLabs.net;
//...
cl.Class5 c5 = cl.Class5();
c5.DoSomething();
Then, instead of using the full namespace, you can simply refer to the CoolLabs.net namespace as cl.
.NET eliminates this nightmare by ensuring that each application has its own copy of the libraries it needs.DLL Hell
If you programmed prior to the .NET era, you've no doubt heard of (maybe even experienced) the phrase DLL Hell. Suppose that you have installed an application on your customer's computer and everything works fine until one day your customer calls and says that your application has suddenly stopped working. Upon probing, you realize that the customer has just downloaded and installed a new application from another vendor. Your application stopped working because one of the libraries (DLLs) that you have been using in your application has been overwritten by the application from the other vendor. And because your application could no longer find the particular DLL that it needs, it ceases to work.
To deploy an assembly as a shared assembly, you need to create a signature for your assembly by performing the following steps:Understanding Cryptography
In the world of cryptography, there are two main types of encryption and encryption algorithms — symmetric and asymmetric.
Symmetric encryption is also sometimes known as private key encryption. With private key encryption, you encrypt a secret message using a key that only you know. To decrypt the message, you need to use the same key. Private key encryption is effective only if the key can be kept a secret. If too many people know the key, its effectiveness is reduced.
Imagine that you are trying to send a secret message to your faraway friend, Susan, using a private key. For Susan to decrypt the secret message, she must know the private key. So you need to send it to her. But if the secrecy of the key is compromised somehow (such as through people eavesdropping on your conversation), then the message is no longer secure. Moreover, if Susan tells another friend about the private key, her friend can then also decrypt the message. Despite the potential weakness of private key encryption, it is very easy to implement and, computationally, it does not take up too many resources.
Private key encryption requires that the key used in the encryption process be kept a secret. A more effective way to transport secret messages to your intended recipient is to use asymmetric encryption (also known as public key encryption). In public key encryption, there is a pair of keys involved. This pair, consisting of a private key and a public key, is related mathematically such that messages encrypted with the public key can only be decrypted with the corresponding private key. The contrary is true; messages encrypted with the private key can only be decrypted with the public key. Let's see an example for each scenario.
Before you send a message to Susan, Susan needs to generate the key pair containing the private key and the public key. Susan then freely distributes the public key to you (and all her other friends) but keeps the private key to herself. When you want to send a message to Susan, you use her public key to encrypt the message and then send it to her. Upon receiving the encrypted message, Susan proceeds to decrypt it with her private key. In this case, Susan is the only one who can decrypt the message because the key pair works in such a way that only messages encrypted with the public key can be decrypted with the private key. Also, there is no need to exchange secret keys, thus eliminating the risk of compromising the secrecy of the key.
The reverse can happen. Suppose Susan now sends a message encrypted with her private key to you. To decrypt the message, you need the public key. The scenario may seem redundant because the public key is not a secret; everyone knows it. But using this method guarantees that the message has not been tampered with and that it indeed comes from Susan. If the message had been modified, you would not be able to decrypt it. The fact that you can decrypt the message using the public key proves that the message has not been modified.
In computing, public key cryptography is a secure way to encrypt information. However, it is computationally expensive, because it is time-consuming to generate the key pairs and to perform encryption and decryption. It is usually used for encrypting a small amount of sensitive information.
An SNK file is a binary file containing the pair of public and private keys.A strong name file is now created in your project (see Figure 15-30).
If you are using Windows Vista, make sure to run the command prompt as Administrator.If the installation is successful, you will see the shared assembly in the Assembly Cache Viewer (see Figure 15-36).
To install different versions of the same assembly to the GAC, simply modify the version number in AssemblyInfo.cs (via the AssemblyVersion attribute), recompile the assembly, and install it into the GAC.Physically, the shared assembly is copied to a folder located under the GAC_MSIL subfolder of the GAC, in the following format:
If you are using Windows Vista, make sure to run regedit as Administrator.Navigate to the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders key. Right-click on the AssemblyFolders key and select New→Key (see Figure 15-39).
Remember to import the System.IO namespace for these two helper functions.public byte[] ImageToByteArray(Image img) {
By default, FTP service is not installed in Windows (note that FTP service is not available on Windows Vista Home editions). To add FTP Service to your computer, select Control Panel→Add or Remove Programs. Click the Add/Remove Windows Component tab, select Internet Information Services (IIS), and click the Details button. Select File Transfer Protocol (FTP) Service, and click OK.To configure the FTP service on your computer, launch the Internet Information Services management console window by typing the command inetmgr in the Run window. Your FTP site should look like Figure 16-2.
Control | Text | Name |
---|---|---|
Button controls (4) | Create Folder | btnCreateFolder |
Remove Folder | btnRemoveFolder | |
Upload Photos | btnUploadPhotos | |
Delete Photo | btnDeletePhoto | |
GroupBox controls (3) | FTP Server | |
Folders | ||
Photos | ||
Label controls (6) | Server Name/IP | |
User Name | ||
Password | ||
Select folder | ||
New folder name | ||
Selected Photo | ||
PictureBox | PictureBox1 | |
TextBox controls (4) | txtFTPServer | |
txtUserName | ||
txtPassword | ||
txtNewFolderName | ||
ToolStripStatusLabel | ToolStripStatusLabel1 | ToolStripStatusLabel1 |
TreeView | TreeView1 |
The source code for this project can be downloaded from Wrox's web site at www.wrox.com.You'll also need to add an ImageList control (ImageList1) to Form1 to contain three images representing an opened folder, a closed folder, and an image file. You can specify these images in the control's Image property (see Figure 16-6).
Control | Property | Value |
---|---|---|
TreeView1 | ImageList | ImageList1 |
PictureBox1 | SizeMode | Zoom |
txtPassword | PasswordChar | "*" |
Name | Type | Scope | Value |
---|---|---|---|
FTP_SERVER | string | User | ftp://127.0.0.1 |
UserName | string | User | anonymous |
Password | string | User | password |
Notice the long string of random characters in the path. The folder name is generated by the system, and each time you have a different folder name.For this project, the user.config file will be stored in a folder with a name like this:
Control | Text | Name |
---|---|---|
Label controls (2) | Print from: | |
to | ||
TextBox controls (2) | txtFrom | |
txtTo | ||
Button controls (2) | Preview | btnPreview |
btnPrint |
The URL http://<server_name>/PhotoViewer/publish.htm is the deployment location of your application. Users who want to install this application through ClickOnce simply need to go to this URL, using their web browser. You provide the URL to your users through email, brochures, and so on.To install the application, click the Install button. You are presented with:
For those of you familiar with the various data source controls (such as SqlDataSource and ObjectDataSource) in ASP.NET 2.0, the LinqDataSource control works much like them. What is special about the LinqDataSourcecontrol is that instead of binding directly to a database (as with the SqlDataSource), it binds to a LINQ-enabled data model. The beauty of this is that you need not write the various complex SQL queries (such as insert, delete, and modify) to use it. Instead, you just need to specify the data model you are working with, and the type of operations you want to perform on it (such as delete, insert, or update) and then the control takes care of performing those operations by itself.The DataClassesDataContext object that you generated earlier is automatically selected for you (see Figure 17-8). Click Next.
Condition | Value |
---|---|
Column | pub_id |
Operator | == |
Source | Control |
Control ID | DropDownList1 |
Attribute | Description |
---|---|
ID | Identifies the ModalPopupExtender control |
TargetControlID | Specifies the control that activates the ModalPopupExtender control |
PopupControlID | Specifies the control to display as a modal popup |
OkControlID | Specifies the control that dismisses the modal popup |
CancelControlID | Specifies the control that cancels the modal popup |
OnOkScript | Specifies the script to run when the modal popup is dismissed with the OkControlID |
OnCancelScript | Specifies the script to run when the modal popup is canceled with the CancelControlID |
BackgroundCssClass | Specifies the CSS class to apply to the background when the modal popup is displayed |
In this particular example, you will get a runtime error if you proceed with the deletion. That's because the titles table is related to the titleauthor table (also part of the pubs database), and deleting a record in the titles table violates the reference integrity of the database.
Pocket PCs | Smartphones |
---|---|
Pocket PC 2000/Pocket PC 2000 Phone Edition | |
Pocket PC 2002/Pocket PC 2002 Phone Edition | Smartphone 2002 |
Windows Mobile 2003 for Pocket PC/Windows Mobile 2003 for Pocket PC Phone Edition | Windows Mobile 2003 for Smartphone |
Windows Mobile 2003 SE (Second Edition) for Pocket PC/Windows Mobile 2003 SE (Second Edition) for Pocket PC Phone Edition | Windows Mobile 2003 SE for Smartphone |
Windows Mobile 5.0 for Pocket PC/Windows Mobile 5.0 for Pocket PC Phone Edition | Windows Mobile 5.0 for Smartphone |
Windows Mobile 6 Classic/Windows Mobile 6 Professional | Windows Mobile 6 Standard |
Version Name | Version Number |
---|---|
1.0 RTM | 1.0.2268.0 |
1.0 SP1 | 1.0.3111.0 |
1.0 SP2 | 1.0.3316.0 |
1.0 SP3 | 1.0.4292.0 |
2.0 RTM | 2.0.5238.0 |
2.0 SP1 | 2.0.6129.0 |
2.0 SP2 | 2.0.7045.0 |
3.5 Beta 1 | 3.5.7066.0 |
3.5 Beta 2 | 3.5.7121.0 |
RTM | 3.5.7283.0 |
Don't forget to download the free Windows Mobile 6 Standard SDK (http://microsoft.com/downloads). You need it to create the application detailed in this chapter.The default Form1 uses the standard form factor of 176×180 pixels. As this application is targeted at users with wide-screen devices, change the FormFactor property of Form1 to Windows Mobile 6 Landscape QVGA.
You can download the images from this book's source code at its Wrox web site.These images will be used by the TreeView control to display its content when the tree is expanded or closed. Hence, associate the ImageList control to the TreeView control by setting the ImageList property of the TreeView control to ImageList1.
Property | Value |
---|---|
Manufacturer | Developer Learning Solutions |
ProductName | RSS Reader v1.0 |
The Windows CE Application Manager is installed automatically when you install ActiveSync on your computer.To locate the Windows CE Application Manager, define the following function named GetWindowsCeApplicationManager():
For more information about the various components in an .ini file, refer to the documentation at http://msdn.microsoft.com/en-us/library/ms889558.aspx.To build the project, right-click on RSSReaderInstaller in Solution Explorer and select Build.
Property | Value |
---|---|
Manufacturer | Developer Learning Solutions |
ProductName | RSS Reader v1.0 |
Property | Value |
---|---|
Author | Wei-Meng Lee |
Manufacturer | Developer Learning Solutions |
ProductName | RSSReader |
Features | Silverlight 1.0 | Silverlight 2 Beta 1 |
---|---|---|
2D Vector Animation/Graphics | X | X |
AJAX Support | X | X |
Cross-Browser (Firefox, IE, Safari) | X | X |
Cross-Platform (Windows, Mac) | X | X |
Framework Languages(Visual Basic, Visual C#, IronRuby, Ironpython) | X | |
HTML DOM Integration | X | X |
HTTP Networking | X | X |
Isolated Storage | X | |
JavaScript Support | X | X |
JSON, REST, SOAP/WS-*, POX, and RSS Web Services (as well as support for Sockets) | X | |
Cross Domain Network Access | X | |
LINQ to Objects | X | |
Canvas Layout Support | X | X |
StackPanel, Grid and Panel Layout Support | X | |
Managed Control Framework | X | |
Full suite of Controls (TextBox, RadioButton, Slider, Calendar, DatePicker, DataGrid, ListBox, and others) | X | |
Deep Zoom Technology | X | |
Managed HTML Bridge | X | |
Managed Exception Handling | X | |
Media — Content Protection | X | |
Media — 720P High Definition (HD) Video | X | X |
Media — Audio/Video Support (VC-1, WMV, WMA, MP3) | X | X |
Media — Image Support (JPG, PNG) | X | X |
Media Markers | X | X |
Rich Core Framework (e.g. Generics, collections) | X | |
Security Enforcement | X | |
Silverlight ASP.NET Controls (asp:media, asp:xaml) | X | X |
Type Safety Verification | X | |
Windows Media Server Support | X | X |
XAML Parser (based on WPF) | X | X |
XMLReader/Writer | X |
When your web browser encounters a Silverlight application and there is no runtime installed, click on the Silverlight icon to download the required version of the runtime.For developing Silverlight 1.0 applications, you need to download the Silverlight 1.0 SDK from www.microsoft.com/downloads.
The positions specified by the Canvas.Left and Canvas.Topattributes of each element or control are relative to its parent control, and not the root control.
Property | Value |
---|---|
Name | EllipsePressed |
Opacity | 0% |
You need Windows Media Player 10 or later for this project to work.The WindowsMedia.wmv file in now contained within a MediaElement control (see also Figure 19-51):
Event Handler | Description |
---|---|
DownloadProgressChanged() | Continuously invoked when the MediaElement control downloads the media from the remote server. It is used to update the red progress bar indicating the progress of the download. |
EllMarkerMouseDown() | Invoked when the user clicks on the marker using the left mouse button. |
EllMarkerMouseUp() | Invoked when the user releases the left mouse button. |
MediaPlayerMouseMove() | Invoked when the mouse moves across the Silverlight page. |
MediaPlayerMouseLeave() | Invoked when the mouse leaves the Silverlight page. |
MediaEnded() | Invoked when the media has finished playing. The media will be reset to its starting position (so is the marker). |
PlayPauseButtonUp() | Invoked when the user clicks on the Play/Pause button. |
Remember to download the Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 tool from www.microsoft.com/downloads before you start the project.
If you have installed the Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 tool, you should see Silverlight in the Project Types list in the New Project dialog.You will be asked how you want to host your application. Select the second option (Generate an HTML test page to host Silverlight within this project), and click OK (see Figure 19-64).
In Visual Studio 2008, the Add Service Reference option replaces the Add Web Reference option. That's because WCF is the preferred way to write your services in Visual Studio 2008. The exception to this is when developing Windows Mobile applications — for those, the Add Web Reference option is available, but the Add Service Reference item is not.Give a name to the Web Service (say, StocksWebService), and click OK. A reference to the Web Service is added to the project (see Figure 20-5).
You'll see more about wsHttpBinding later in this chapter.Close the WCF Test Client window. Back in Visual Studio 2008, edit the IService1.cs file, adding the getAge() function signature to the IService1 interface:
By default, the [OperationContract] attribute specifies a request/response messaging pattern for the operation.After the class definition for CompositeType, define the following data contract called Contact:
Binding | Description |
---|---|
BasicHttpBinding | Most basic; limited security and no transactional support. Compatible with traditional ASMX Web Services. |
WSHttpBinding | More advanced HTTP with WSE security. |
WSDualHttpBinding | Extends WSHttpBinding and includes duplex communications. |
WSFederationHttpBinding | Extends WSHttpBinding and includes federation capabilities. |
NetTcpBinding | Used for TCP communication; supports security, transaction, and so on. |
NetNamedPipeBinding | Used for named pipe communication; supports security, transaction, and so on. |
NetPeerTcpBinding | Supports broadcast communication. |
MexHttpBinding | Publishes the metadata for the WCF service. |
NetMsmqBinding | Used for MSMQ. |
MsmqIntegrationBinding | Used for MSMQ. |
Contract | Defines |
---|---|
Service | All the operations contained in a service. |
Operation | All the methods, parameters, return types, and so on. |
Message | How messages are formatted. For instance, data should be included in SOAP header or SOAP message body, and so on. |
Fault | Faults an operation may return. |
Data | The type of data used and required by the service. |
If you host a WCF service using an executable or Windows service, that WCF service is said to be self-hosted.
In this example, the WCF service is hosted by the ASP.NET Development Server, a web server shipped with Visual Studio 2008. Because the service is hosted by a web server, the NetTcpBinding binding is not supported.Edit the Web.config file by right-clicking it in Solution Explorer and selecting Edit WCF Configuration. (You can also launch the WCF Service Configuration Editor by selecting Tools→WCF Service Configuration Editor.)
Property | Value |
---|---|
Address | asmx |
Binding | basicHttpBinding |
Contract | MultipleEndpointsService.IService1 |
Name | Binding | Description |
---|---|---|
WS | wsHttpBinding | The wsHttpBinding: Uses the WS-* protocols. Security is at the message level. Uses additional handshake messaging. Supports reliable session. Messages exchanged between the client and the server are encrypted. |
[Empty Name] | mexHttpBinding | Publishes the metadata for the WCF service, allowing clients to retrieve the metadata using a WS-Transfer GET request or an HTTP/GET request using the ?wsdl query string. By default, every WCF service created using Visual Studio 2008 has this endpoint to allow clients to request the service's metadata. |
BASIC | basicHttpBinding | The basicHttpBinding: Supports old ASMX-style (based on WS-BasicProfile1.1) Web Services call. Does not support secure messaging (no WS enhancements). Does not support reliability and ordered delivery. Calls may be lost and the client simply time out. Calls may not be ordered correctly. Security is at the transport layer (SSL, for instance). Allows compatibility with ASMX Web Services and clients. |
The SetMessage() operation uses the one-way messaging pattern because clients simply send messages to the sender and do not need to wait for a response from the server.This operation allows clients to send a message to the WCF service.
Edit the App.config file, using the WCF Service Configuration Editor (you can also select it from Tools→WCF Service Configuration Editor).Service Behaviors: InstanceContextMode
When a WCF Service receives a message, the message is dispatched to an object's instance methods:
□ A single instance of the receiver may be created for all clients, or
□ A single instance of the receiver may be created for each client.
The InstanceContextMode property specifies the number of service instances available for handling calls that are contained in incoming messages. It can be one of the following:
□ Single — Every received message is dispatched to the same object (a singleton).
□ Percall — Every received message is dispatched to a newly created object. This is the default.
□ PerSession — Messages received within a session (usually a single sender) are dispatched to the same object.
□ Shareable — Messages received within a session (can be one or more senders) are dispatched to the same object.
Property | Value |
---|---|
Address | net.tcp://localhost:1234/MessageService |
Binding | netTcpBinding |
In this example, the WCF service is hosted by the Windows Form application, at port 1234, using the TCP protocol.
In this example, the WCF service will be hosted by the WCF Service Host, a utility provided by Visual Studio 2008.In the IService1.cs file, define the following service and data contracts:
Operation | Description |
---|---|
SetSeatStatus | Allows clients to book seats. Takes in a string containing the seats to be booked. |
RegisterClient | Registers a client when it connects to the service. Takes in a GUID so that the service can uniquely identify a client. |
UnRegisterClient | Unregisters a client when it disconnects from the service. Takes in the client's GUID. |
For simplicity of demonstration, the following shortcuts are made:Service Behaviors — ConcurrencyMode
When messages are received by a WCF service, you can set how threads are used to manage all received messages:
□ One thread can be used to access the receiver object(s) at a time, or
□ Multiple threads can be used to access the receiver object(s) concurrently.
How you handle all incoming messages is specified using the ConcurrencyMode property of the [ServiceBehavior] attribute, which can assume one of the following values:
□ Single (default) — Only one thread can access the receiver object at a time.
□ Multiple — Multiple threads can access the receiver object(s) concurrently.
□ Reentrant — Only one thread can access the receiver object at a time, but callbacks can reenter that object on another thread.
When you use the Multiple mode on the service, take special care to make sure that threads are synchronized properly and that critical regions are locked when a threading is accessing it.
Property | Value |
---|---|
Address | net.tcp://localhost:5000/TicketingService |
Binding | NetTcpBinding |
Keyword | Description |
---|---|
abstract | A modifier that can be used with classes, methods, properties, indexers, and events. Use it to indicate that a class is intended to be used as a base class of other classes, and abstract methods must be implemented by classes that derive from the abstract class. |
as | An operator that performs conversion between compatible reference types. |
base | Used to access members of a base class from a derived class. |
bool | A C# alias of the System.Boolean .NET Framework type. Its value can either true, false, or null. |
break | Used to transfer control out of a loop or switch statement. |
byte | Specifies a data type that can stores unsigned 8-bit integer values from 0 to 255. |
case | Used together with the switch statement. It specifies the value to be matched so that control can be transferred to the case statement. |
catch | Used with a try block to handle one or more exceptions. |
char | Specifies a data type that can store a 16-bit Unicode character from U+0000 to U+ffff. |
checked | Used to explicitly enable overflow-checking integer operations. |
class | Used to declare classes. |
const | Used to specify a field or variable whose value cannot be modified. |
continue | Used within a loop such that control is transferred to the next iteration. |
decimal | Specifies a data type representing a 128-bit data. It can approximately represent a number from ±1.0×10-28 to ±7.9×1028. |
default | Used within a switch statement to indicate the default match if none of the other case statements is matched. Can also be used in generics to specify the default value of the type parameter. |
delegate | Used to declare a reference type variable that references a method name/anonymous method. |
do | Executes a block of code repeatedly until a specified expression returns false. Used together with the while keyword to form a do-while statement. |
double | Specifies a data type that represents a 64-bit floating point number. It can approximately represent a number from ±5.0×10-324 to ±1.7×10308. |
else | Used with the if keyword to form an if-else statement. else defines the block that will be executed if the expression specified in the if statement is evaluated to false. |
enum | Used to define an enumeration. |
event | Used to define an event within a class. |
explicit | Defines a cast operation that requires the programmer to explicitly select the cast to be performed. |
extern | Declares a method that is implemented externally. |
false | Used as either an operator or as a literal. One of the possible values in a bool variable. |
finally | Used in a try-catch block to contain code that cleans up the code even if an exception occurs. Statements contained within a finally block are always executed. |
fixed | Prevents the garbage collector from relocating a movable variable. |
float | Specifies a data type that represents a 32-bit floating point number. It can approximately represent a number from ±1.5×10-45 to ±3.4×1038. |
for | Encloses a block of statements that will be executed repeatedly until a specified expression returns false. |
foreach | Used to iterate through a collection of items. |
goto | Used to transfer control of a program to a labeled statement. |
if | Determines if a statement (or block of statements) is to be executed based on the result of a Boolean expression. |
implicit | Used to declare an implicit cast operation. |
in | Used in a foreach statement to specify the collection you want to iterate through. |
int | Specifies a data type that represents a signed 32-bit integer number. It can represent a number from -2,147,483,648 to 2,147,483,647. |
interface | Used to define an interface, which is a definition that contains the signatures of methods, delegates, and events. An interface does not contain any implementation. |
internal | An access modifier to indicate a member that can only be accessed within files in the same assembly. |
is | Used to check if an object is compatible with a given type. |
lock | Marks a statement block as a critical section so that other threads cannot execute the block while the statements within the block are being executed. |
long | Specifies a data type that represents a signed 64-bit integer number. It can represent a number from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. |
namespace | Used to organize your code so that it belongs to a globally unique type. |
new | Used to create objects and invoke a class's constructor. Also can be used to explicitly hide a base class's member in a derived class. When used in a generic declaration, it restricts types that might be used as arguments for a type declaration. |
null | Represents a null reference that does not refer to any object. |
object | A C# alias of the System.Object .NET Framework type. |
operator | Used to overload a built-in operator or provide a conversion operator. |
out | Indicates arguments that are to be passed by reference. It is similar to ref, except that ref requires the variable to be initialized before it is passed. |
override | Extends or modifies the abstract or virtual implementation of an inherited method, property, indexer, or event. |
params | Specifies a parameter array where the number of arguments is variable. |
private | An access modifier used to indicate a member that can only be accessed within the body of the class or struct in which it's declared. |
protected | An access modifier used to indicate a member that can only be accessed within its class and derived classes. |
public | An access modifier used to indicate a member that can be accessed by all code. |
readonly | A modifier that indicates fields that can only be initialized at declaration or in a constructor. |
ref | Indicates arguments that are to be passed by reference. |
return | Terminates execution of a method and returns control to the calling method. |
sbyte | Specifies a data type that represents a signed 8-bit integer number. It can represent a number from -128 to 127. |
sealed | Specifies a class that does not allow other classes to derive from it. |
short | Specifies a data type that represents a signed 16-bit integer number. It can represent a number from -32,768 to 32767. |
sizeof | Used to obtain the size in bytes for a value type. |
stackalloc | Used in an unsafe code context to allocate a block of memory on the stack. |
static | A modifier to indicate that a member belongs to the type itself, and not to a specific object. |
string | Specifies a data type that represents a sequence of zero or more Unicode characters. Also an alias for the System.String .NET Framework type. |
struct | Denotes a value type that encapsulates a group of related variables. |
switch | A control statement that handles multiple selections by matching the value of the switch with a series of case statements. |
this | Refers to the current instance of the class. Also used as a modifier of the first parameter of an extension method. |
throw | Used to invoke an exception during runtime. |
true | Used either as an operator or as a literal. One of the possible values in a bool variable. |
try | Indicates a block of code that may cause exceptions. Used with one or more catch blocks to handle the exceptions raised. |
typeof | Used to obtain the System.Type object for a type. |
uint | Specifies a data type that represents an unsigned 32-bit integer number. It can represent a number from 0 to 4,294,967,295. |
ulong | Specifies a data type that represents an unsigned 64-bit integer number. It can represent a number from 0 to 18,446,744,073,709,551,615. |
unchecked | Used to suppress overflow-checking for integral-type arithmetic operations and conversions. |
unsafe | Denotes an unsafe context, which is required for any operation involving pointers. |
ushort | Specifies a data type that represents an unsigned 16-bit integer number. It can represent a number from 0 to 65,535. |
using | A directive for creating a namespace alias or importing namespace references. It is also used for defining a scope at the end of which an object will be disposed. |
virtual | An access modifier to indicate a method, property, indexer, or event declaration and allow for it to be overridden in a derived class. |
volatile | Indicates that a field might be modified by multiple threads that are executing at the same time. |
void | Specifies that a method does not return any value. |
while | Executes a statement or a block of statements until a specified expression evaluates to false. |
Keyword | Description |
---|---|
from | Used in a LINQ query. A query expression must begin with a from clause. |
get | Defines an accessor method in a property or indexer. It retrieves the value of the property or indexer element. |
group | Used in a LINQ query and returns a sequence of IGrouping<(Of <(TKey, TElement>)>) objects that contain zero or more items that match the key value for the group. |
into | Used in a LINQ query and can be used to create a temporary identifier to store the results of a group, join, or select clause into a new identifier. |
join | Used in a LINQ query for associating elements from different sources. |
let | Used in a LINQ query to store the result of a subexpression to be used in a subsequent clause. |
orderby | Used in a LINQ query to sort the result of a query in either ascending or descending order. |
partial | Denotes that the definition of a class, struct, or interface is split into multiple files. Also denotes that a method's signature is defined in one partial type and its definition is defined in another partial type. |
select | Used in a LINQ query to specify the type of values that will be produced when the query is executed. |
set | Defines an accessor method in a property or indexer. It assigns a value to the property or indexer element. |
value | An implicit parameter in a set accessor. It is also used to add or remove event handlers. |
where | Used in a LINQ query to specify which elements from the data source will be returned in the query expression. |
yield | Used in an iterator block to provide a value to the enumerator object or to signal the end of iteration. |
Due to the continual development of the Sandcastle project, these screen shots may differ from what you actually see on your screen.Finally, you should run the BuildReflectionData.bat batch file (located in C:\Program Files\EWSoftware\Sandcastle Help File Builder) to build the reflection data for the version of the .NET runtime you are using.
If the C:\Program Files\Sandcastle\Data folder already contains a folder called Reflection, you need to delete that folder before running this batch file.
Ensure that your Sandcastle project is saved in a folder whose name does not contain any special characters (such as #, ?, &, and +). If not, you won't be able to view the documentation properly.Figure C-12 shows the generated documentation (the tree view on the left is shown with all the nodes expanded to reveal the full documentation).
Ñïàñèáî, ÷òî ñêà÷àëè êíèãó â áåñïëàòíîé ýëåêòðîííîé áèáëèîòåêå BooksCafe.Net
Îñòàâèòü îòçûâ î êíèãå
Âñå êíèãè àâòîðà