Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / Premier Press - C# Professional Projects

.pdf
Скачиваний:
443
Добавлен:
12.02.2016
Размер:
14.7 Mб
Скачать

78

Part II

HANDLING DATA

 

 

 

{

 

 

 

 

 

 

string string1 = “New String”;

 

 

object obj1 = string1;

 

 

 

Console.WriteLine (obj1);

 

 

}

 

 

}

 

 

 

This code initializes a string type variable with the value “New String” and then

 

 

 

Y

 

creates an instance obj1 of the type object. The value of string1 is now copied to

 

 

L

 

the new instance of object and is displayed in the Console window.

 

 

F

 

In addition to implicit data conversion by using boxing, you can use boxing to

 

 

M

 

explicitly convert data. Look at the following example of an explicit data conver-

sion by using boxing. A string string1 = “New String”;E

object obj1 = (object) string1;

This code uses theTcast operator to explicitly convert string1 to an object.

Similar to boxing, unboxing is also a data type conversion technique. Unboxing is used to explicitly convert an object type to a value type.The technique of unboxing is opposite to that of boxing. However, to unbox a reference type, it is essential that you first box the value type. Unboxing can be only of the explicit conversion type. Consider the following example to understand unboxing.

string string1 = “New String”;

object obj1 = string1;

string string2 =(string) obj1;

While unboxing from one type to another, you need to take care that the resultant variable has enough space to store the initial type. For example, if you try to unbox as byte variable type from an integer variable type, it may result in an error. In this case, you box a 32-bit integer type value to an 8-bit sbyte type value. Subsequently, you unbox a smaller value to a larger value. Therefore, the following code generates an error in C#.

int x = 100;

object y = (object) x;

sbyte z = (sbyte) y;

Team-Fly®

MORE ABOUT COMPONENTS

Chapter 4

79

 

 

 

In addition to data conversion statements, C# provides you with certain commands that influence the compilation of your code. These commands are called preprocessor directives.

Preprocessor Directives

In C#, preprocessor directives are commands that are not executed. However, these commands influence the process of compilation of code. For example, if you do not want the compiler to execute certain part of the code, you can mark the code by using the preprocessor directive. To declare a preprocessor directive, use a # sign, such as:

# preprocessor name

Some of the commonly used preprocessor directives provided by C# are discussed in the following sections.

#region and #endregion

C# provides you with the #region preprocessor directive that you can use to define a set of statements to be executed as a block. The #endregion directive marks the end of such a set of statements. For example:

#region Region1

string EmpName, EmpAddress;

int Empcode, Empphone;

#endregion

Here, Region1 is the name given to the set of statements marked by the #region preprocessor directive.

#define and #undef

The #define and #undef preprocessor directives are used to define and remove the definition of a symbol, respectively. These preprocessor directives are similar to a variable declaration statement. However, the symbols created by these directives

80

Part II

HANDLING DATA

 

 

 

do not exist. You can use the #define and #undef directives to declare symbols. However, you cannot create symbols by using these declarations. For example:

#define symbol1

and

#undef symbol1

The first line of code defines a symbol with the name symbol1, and the second line of code deletes the definition of symbol1.

#if, #endif, #else, and #elif

As discussed earlier, preprocessor directives can be used to prevent a compiler from executing certain sections of code. Similarly, you can also use certain preprocessor directives to conditionally compile certain sections of code. To do this, C# provides you with the #if, #endif, #else, and #elif preprocessor directives. These directives are commonly called conditional preprocessor directives.

The syntax of an #if-#endif command is as follows:

#if symbol1

-----------------

#endif

Here, symbol1 is a symbol declared by the #define preprocessor directive. The statements in the #if loop are executed if the symbol following the #if keyword has been previously declared using the #define command. If symbol1 has not been previously declared, the compiler reaches the end of #endif statement.

You can also direct the compiler to execute a set of statements if the symbol is not defined.This can be done using the #elif and #else preprocessor directives. Look at the following example.

#define Symbol1

class Class1

{

#if Symbol1

Console.WriteLine (“Symbol1 exists”)

MORE ABOUT COMPONENTS

Chapter 4

81

 

 

 

#else

Console.WriteLine (“Symbol1 does not exist”)

#endif

}

TIP

You can also use nested #if-#elif loops.

#error and #warning

The #error and #warning preprocessor directives are used to raise an error and a warning, respectively. If the compiler encounters the #warning preprocessor directive, it issues a warning to the programmer by displaying the text in the #warning statement. The compiler then resumes with compilation of the code. However, if the compiler comes across an #error preprocessor directive, it generates an error and stops executing the code. The #error and #warning preprocessor directives are generally used with the conditional preprocessor directives discussed previously.

Look at the following example to have better understanding of the preprocessor directives used in C#.

#define Symbol1 using System; public class Class1

{

public static void Main()

{

#if Symbol1

Console.WriteLine(“Symbol1 is defined”);

#else

#warning Symbol1 is not defined

#endif

}

}

The output of the previous code is shown in Figure 4-2.

82

 

Part II

HANDLING DATA

 

FIGURE 4-2 Ouput of the previous code

Summary

In this chapter, you learned about arrays and collections. An array is a data structure used to store a number of variables and has one or more indices attached to it. A collection is defined as a group of objects that you can access using the foreach loop. An array is a special type of collection in C#. Next, you learned about indexers, which are members that allow you to access objects as if they were the elements of an array.

This chapter also covered techniques to type cast variables into objects and vice versa. To do this, you used the techniques of boxing and unboxing. Boxing is used to convert a value type to a reference type. Unboxing does the opposite, by converting a reference type to a value type. Finally, you learned about preprocessor directives in C#. These directives are commands that are not executed by the C# compiler. However, these commands affect the process of code compilation.

Chapter 5

Attributes

and Properties

84

Part II

HANDLING DATA

 

 

 

In Chapter 3, “Components of C#,” you learned about classes and the methods implemented with classes. In this chapter, you will learn about attributes and

properties that are used to store extra information about classes.

Attributes

Attributes are used to store additional information about methods and classes. You have extensively used attributes in the previous chapters. For example, the class and method modifiers that store accessibility information about classes and methods, respectively, are attributes placed on these entities. Attributes are elements used with methods, classes, assemblies, and Web services. Attributes can also be used with arguments of a method.

Attributes are similar to preprocessor directives, as the attributes are not compiled during the execution of a program. However, attributes are useful because they provide you with additional information about resources in a program. You can retrieve this information at run time and can then document the information for future use. To retrieve the information stored in attributes, you need to create instances of the Attribute class. You will learn about the Attribute class later in this chapter.

Declaring Attributes

Attributes are declared using an attribute declaration statement, such as:

[attribute name (attribute parameters)]

This statement includes the name of the attribute, followed by the list of parameters in parentheses. You can also define an attribute that does not take any parameter. The attribute declaration statement is immediately followed by the declaration of the entities for which the attribute is defined.

All attributes in C# are derived from the Attribute class. The Attribute class is global to the .NET Framework.This implies that if you declare an attribute, it can

ATTRIBUTES AND PROPERTIES

Chapter 5

85

 

 

 

be used by any class defined in the .NET Framework. The next section will discuss the Attribute class in detail.

Attribute Class

You can define an attribute class to store user-defined attributes. The attribute class that you declare also contains information about the entities on which you can place the attributes defined in the class. All attribute classes are derived from the abstract class Attribute. The Attribute class is contained in the System namespace.

Once an attribute is declared in the attribute class, you can place the attribute on any entity. An attribute class can be of the following types:

Single-use attribute class. The attributes declared in a single-use attribute class cannot be placed more than once on the same entity.

[color (“Green”)] class Car

{

--------------

}

Multiuse attribute class. The attributes declared in a multiuse attribute class can be placed more than once on the same entity. The following example shows that two values of the attribute color can be placed on the class Car.

[color (“Green”), color (“Blue”)] class Car

{

--------------

}

As discussed earlier, you can create attributes that take parameters. To perform this task, you need to define a parameter list in the default constructor of the attribute class. The attribute class takes two types of parameters. These parameters will now be described in detail.

86

Part II

HANDLING DATA

 

 

 

Attribute Parameters

The parameters used with attributes include the following:

Positional parameters. Parameters that are declared in the public constructor of the attribute class are called positional parameters. A positional parameter of an attribute consists of an attribute argument expression and is used with the required parameters.

Named parameters. Parameters that are declared in the non-static, public read-write field or property of an attribute class are called named parameters. They are used to read and write values to an attribute. You use named parameters to define optional parameters of an attribute class.

TIP

If you need to declare both positional and named parameters for the same attribute class, the positional parameters are followed by the named parameters.

You can also specify the data types of both positional and named parameters. The attribute parameter types supported by C# are int, short, long, byte, char, string, bool, double, float, object, type, and enum. You have learned about these data types in Chapter 2, “C# Basics,” in the section “Variable Data Types.”

Until now, you have seen that you can define custom attributes and the custom attribute class. However, C# also contains certain default attributes, as discussed in the next section.

Default Attributes

The C# compiler explicitly recognizes the default parameters provided by C# and compiles the program code accordingly. Following are some of the most commonly used default attributes.

Obsolete attribute. As the name suggests, the Obsolete attribute is used to mark an element that you should no longer use in any program code. The Obsolete attribute is the alias defined for the ObsoleteAttribute class in the System namespace. To prevent a programmer from using the code marked obsolete, you can generate an error or a warning by passing

ATTRIBUTES AND PROPERTIES

Chapter 5

87

 

 

 

the error or warning as a parameter to the Obsolete attribute. For example:

[Obsolete (“Do not use this method in the code”), true]

Here, the first parameter contains the error or warning message to be displayed. The second parameter of the type bool specifies whether an error or a warning will be generated. The value of true specifies that the compiler will generate an error and stop the execution of the program. However, if the value of this parameter is false, the compiler only generates a warning.

Conditional attribute. The Conditional attribute is used to conditionally compile a set of statements marked with the Conditional attribute. You can also mark a method with the Conditional attribute. The method or set of statements will then be compiled only if a symbol is defined. Consider the following example:

[Conditional (“Symbol1”)] public void Method1()

{

------------

}

In this code, the call to the function Method1 will only be made if Symbol1 is defined. Symbol1 can be defined using the #define preprocessor directive. You have learned about the preprocessor directives available in C# in Chapter 4, “More about Components,” in the section “Preprocessor Directives.”

AttributeUsage attribute. The AttributeUsage attribute is used with the attribute class. This attribute takes parameters that store information about the attribute class. To know more about the AttributeUsage attribute, consider the following example:

[AttributeUsage (AttributeTargets.Class | AttributeTargets.Structs,

AllowMultiple = true, Inherited = true)]

public class Attribute1 : Attribute

{

-----------

}