
C# ПІДРУЧНИКИ / c# / Premier Press - C# Professional Projects
.pdf
88 |
Part II |
HANDLING DATA |
|
|
|
The first parameter of the AttributeUsage attribute is AttributeTargets, which defines the list of entities for which you can declare the attribute. The AttributeTargets parameter can take more than one value and is of the type enum. You can also use AttributeTargets.All to make the attribute applicable to all the entities specified in your program code.
The second parameter of the AttributeUsage attribute is the bool type parameter named AllowMultiple. If this parameter is set to false, the attribute class is a single-use attributeYclass. The true value of this parameter indicates that the class is a multi-use attribute class.
L F parameter named InheritedM. The Inherited parameter specifies whether
The third parameter of the AttributeUsage attribute is another bool type
the attribute can be used by the derived classes of the base class for which the attributeAis defined. To make the attribute accessible to the derived classes,Ethe value of this parameter is set to true. However, the
default value of the Inherited parameter is false, which prevents the use T of the attribute by the derived classes.
The next section will discuss properties, which are used to access an attribute of an element.
Properties
You have seen that you can declare attributes for all the elements in your program code. However, to access an object or a class, you need to declare a property member for that object. Just like attributes, properties also store information about objects. In previous discussions, you have been using properties with almost every object that you defined. For example, the name of an object is its property. However, properties cannot be used to define storage locations.
Declaring Properties
Properties are declared using the property declaration statement, such as:
<modifier> <type> <property name>
{
------------
}
Team-Fly®

ATTRIBUTES AND PROPERTIES |
Chapter 5 |
89 |
|
|
|
The property modifier includes access modifiers, such as public, private, protected, and internal. In addition, the property modifier includes the new, static, override, abstract, and sealed modifiers. You can use more than one modifier in a property declaration statement. Because a property is not a variable, you cannot pass a property as a ref or an out parameter.
The property declaration statement also includes the type of the property, followed by its name of the property. Inside the block of the property declaration statement, you include the accessor declaration statements. These statements are executable statements that define the actions to be performed while reading and writing values to an attribute.
Each property that you declare has accessors associated with it. These accessors define statements that enable you to read and write values to a property. The accessors used with properties will now be discussed in detail.
Accessors
The accessors used with properties are the get and set accessors. These accessors are followed by a block of statements to be executed when the accessor is invoked.
get accessor. The get accessor is a method used to read values to a property. The get accessor does not take any parameter, but it returns a value of the data type specified in the property declaration statement. In the body of the get accessor, you need to include a return or a throw statement. This prevents the control of execution from going out of the body of the get accessor. The expression that follows the get accessor in the definition of the property must be of a specific type. You should be able to implicitly convert this type into the data type specified in the property declaration statement.
set accessor. The set accessor is a method used to write values to a property. The set accessor takes a single implicit parameter named value but does not return any value. Therefore, the set accessor is a void method with a parameter that specifies the value to be written. The return statement in the set accessor is not followed by any expression.

90 |
Part II |
HANDLING DATA |
|
|
|
To understand the get and set accessors, look at the following example:
public class Car
{
string color: public string Color1
{
get
{
return color;
}
set
{
color = value;
}
}
}
This code declares a property Color1 for the class Car. The property declaration statement contains the get and set accessors. When you need to read data from the property, the get accessor is implicitly invoked. The get accessor returns a variable color of the same data type as that of the property. The variable color stores the value read by using the get accessor.
When you need to write a value to a property, the set accessor is invoked.The set accessor takes a parameter named value that specifies the value to be written to the variable color. To w rite the value Green to the property, you simply need to write the following statement:
Car car1 = new Car();
car1.color = “Green”;
Based on the type of accessors defined in the property declaration statement, properties are classified as follows.
read-only property. The property definition of a read-only property contains only the get accessor.
write-only property. The property definition of a write-only property contains only the set accessor.
read-write property. The property definition of a read-write property contains both the get and set accessors.

ATTRIBUTES AND PROPERTIES |
Chapter 5 |
|
91 |
|
|||
|
|
|
|
In addition to this classification, properties are classified based on the modifier specified in the property declaration statement. As discussed earlier, property modifiers include access modifiers and the new, static, override, abstract, and sealed modifiers.
Types of Properties
C# supports the following properties based on the type of modifier used in the property declaration statement.
Static property. A property that is declared with a static modifier is a static property. A static property cannot be referred by a specific instance of a class. You cannot use the abstract, override, and virtual modifiers with a static property.
Instance property. A property that is not declared with an explicit static modifier is an instance property. An instance property is referred by a specific instance of a class and is also known as a non-static property.
Summary
In this chapter, you learned about attributes and properties. Attributes are elements used with methods and classes to store additional information about them. Attributes can also be used with the arguments of a method. To retrieve the information stored in attributes, you need to create instances of the Attribute class. All attribute classes are derived from the abstract class Attribute in the System namespace.
Next, you learned about the default attributes provided by C#. These default attributes include the Obsolete, Conditional, and AttributeUsage attributes. The C# compiler explicitly identifies the default parameters provided by C# and compiles the program code accordingly.
Finally, you learned about properties that are used to access an attribute of an element. Each property that you declare has accessors associated with it. These accessors define statements that enable you to read and write values to a property. The accessors used with properties are the get and set accessors.
This page intentionally left blank

Chapter 6
Threads

94 |
Part II |
HANDLING DATA |
|
|
|
In this chapter, you will be introduced to threads. In addition, you will learn to create and work with threads. This chapter introduces you to the Thread class, which is a .NET base class.This class helps you to create and manipulate threads in applications. This chapter also discusses the states and priorities of threads. Finally, the chapter introduces you to the synchronization of variables across
threads.
Introduction to Threads
Threads are a well-known concept to C and C++ programmers. A thread is a basic unit of the execution of a program. In other words, a thread is the smallest unit to which the operating system allocates processor time. A thread decides the sequence of execution of a program and is very useful for executing complex applications or even multiple applications simultaneously. In addition, you can have a single application containing multiple threads. When the C# compiler executes a multithreaded application, several threads are executed simultaneously. This makes the execution of a complex application less time-consuming.
In a multithreaded application, you can execute multiple activities simultaneously. For example, consider a situation in which you execute a print command for printing 100 pages. Printing 100 pages takes a substantial amount of time. Therefore, you can have two threads working simultaneously on the system. One thread can be used for printing and the other thread can be used to perform any other activity, such as working in a Word document or a spreadsheet.
All the applications that you create involve one or more threads. However, there are some situations in which threads can be used very effectively. Following are examples of some of these situations.
As discussed earlier, you use threads to perform operations that can be time-consuming. In such cases, you can create two threads, a worker thread and a user thread. The worker thread performs time-consuming operations, and the user thread manages user interactions. For example, you can create a worker thread to print 100 pages while the user thread enables you to work in a Word document.

THREADS |
Chapter 6 |
|
95 |
|
|||
|
|
|
|
You can also use threads to transfer data over the network. For example, you need to transfer volumes of data from one branch office to another. In this case, you can create a thread to connect to the server in the other branch.
You also use threads when you need to execute an application that performs more than one operation. For example, when a data entry operator enters data into a database, this data should be updated automatically in the master database. In this case, you can have a worker thread and a user thread. The user thread accepts the input from the user while the worker thread updates the records in the master database.
You have seen that using threads in your application allows you to perform multiple activities simultaneously. However, extensive use of threads in a single application may even deteriorate the performance of your application. To understand this, let us look at the process of execution of threads. Executing threads requires the use of several operating system resources.These resources execute a thread for a very short period of time, known as the time slice of the thread. After executing the thread for this time slice, the Windows operating system chooses another thread to execute.This process of executing multiple threads for a given time slice is called preemptive multitasking. If you have multiple threads in a single application, the operating system spends time switching between various threads after a time slice, which may in turn reduce the performance of the application.
By now, you know that your application can have as many threads as required.The next section looks at creating threads for your application.
Creating Threads
A thread that you create is an instance of the Thread class. The Thread class is a class in the .NET Framework class library and is located in the System.Threading namespace. Therefore, to create an instance of the Thread class, you first need to import the System.Threading namespace. You can then create the object of the Thread class that represents a thread. You can continue to add threads to your application by simply creating multiple instances of the object of the Thread class.
To create a thread, you need to declare an instance of the Thread class and provide it with the details of the method with which the execution of the thread starts. To do so, you can use the public void delegate named ThreadStart() of the System.Threading namespace. You have learned about delegates in Chapter 1, “Overview of the .NET Framework,” in the section “Delegates.”

96 |
Part II |
HANDLING DATA |
|
|
|
Consider the following example.
using System;
using System.Threading; class Class1
{
public void Method1()
{
Console.WriteLine(“Method1 is the starting point of execution of the thread”);
}
public static void Main()
{
Class1 newClass = new Class1();
Thread Thread1 = new Thread(new ThreadStart(newClass.Method1));
}
}
Here, an instance of the Thread class, Thread1, is created. The ThreadStart() delegate specifies the name of the method, Method1, with which the execution of Thread1 starts. Method1 is a public void function defined in Class1. However, creating an instance of the Thread class does not make the thread functional. To start the thread, you need to call the Start() method. The following code shows the syntax for calling the Start() method.
Thread1.Start();
TIP
Because the threads that you define can be used across applications, it is advisable that you give a relevant name to your thread.This enables other programmers to reuse the functionality provided by your thread. To give a relevant name to your thread, you can change the value of the Name property of the thread.
The following code defines a worker thread for updating the records in the master database. It will give the thread a meaningful name, such as
Thread.

THREADS |
Chapter 6 |
97 |
|
|
|
Thread Thread1 = new Thread(new ThreadStart(newClass.Method1));
Thread1.Name = “Update Records Thread”;
The previous code snippet creates an instance of the Thread class with the name Thread1 and then assigns a name Update Records Thread to the thread.
In addition to the Name property that is used to give a meaningful name to a thread, you can use properties to know the status of the executing threads.These properties are defined in the Thread class of the System.Threading namespace.
IsAlive property. The IsAlive property is used to specify that the execution of a thread is complete or the thread is still working. The IsAlive property returns a Boolean value of true for the thread that is working and false for the thread that is not executing.
ThreadState property. The ThreadState property indicates the execution status of a thread. In other words, it returns a value specifying whether the execution of the thread has started or not. You will learn about the states of a thread later in this chapter.
Aborting Threads
You have learned how to create and execute a thread. However, sometimes you may need to stop a running thread. Consider the same old example in which you executed a print command for 100 pages. In this case, a thread is executed to print the required pages. If you need to print some other urgent page, you need to stop the previous print command or, in other words, abort the thread that is printing 100 pages. This section discusses aborting a running thread.
C# provides you with a base class, the Thread class, that you can use to perform several operations with threads. The Thread class contains several predefined methods that enable you to work with threads. To abort a thread, you use the Abort() method of the Thread class. The Abort() method has the following syntax:
Thread1.Abort();
Here, Thread1 is the instance of the Thread class. The Abort() method does not take any parameters. When you call the Abort() method, the C# compiler might not kill the thread instantaneously. To understand why the C# compiler takes time to kill the thread, you first need to understand how the Abort() method is executed.