Xem mẫu

170 Part II Understanding the C# Language You can access and modify the value held in the variable i through the pointer variable pi like this: *pi = 100; This code updates the value of the variable i to 100 because pi points to the same memory location as the variable i . One of the main problems that developers learning C and C++ have is understanding the syntax used by pointers . The * operator has at least two meanings (in addition to being the arithmetic multiplication operator), and there is often great confusion about when to use & rather than * . The other issue with pointers is that it is easy to point somewhere invalid, or to forget to point somewhere at all, and then try to reference the data pointed to . The result will be either garbage or a program that fails with an error because the operating system detects an attempt to access an illegal address in memory . There is also a whole range of security flaws in many existing systems result-ing from the mismanagement of pointers; some environments (not Microsoft Windows) fail to enforce checks that a pointer does not refer to memory that belongs to another process, opening up the possibility that confidential data could be compromised . Reference variables were added to C# to avoid all these problems . If you really want to, you can continue to use pointers in C#, but you must mark the code as unsafe . The un-safe keyword can be used to mark a block of code, or an entire method, as shown here: public static void Main(string [] args) { int x = 99, y = 100; unsafe { swap (&x, &y); } Console.WriteLine("x is now {0}, y is now {1}", x, y); } public static unsafe void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } When you compile programs containing unsafe code, you must specify the /unsafe option . Unsafe code also has a bearing on how memory is managed; objects created in unsafe code are said to be unmanaged . We discuss this issue in more detail in Chapter 14 . Chapter 8 Understanding Values and References 171 In this chapter, you learned about some important differences between value types that hold their value directly on the stack and reference types that refer indirectly to their objects on the heap . You also learned how to use the ref and out keywords on method parameters to gain access to the arguments . You saw how assigning a value (such as the int 42) to a variable of the System.Object class creates a boxed copy of the value on the heap and then causes the System.Object variable to refer to this boxed copy . You also saw how assigning a variable of a value type (such as an int) to a variable of the System.Object class copies (or unboxes) the value in the System.Object class to the memory used by the int . If you want to continue to the next chapter Keep Visual Studio 2010 running, and turn to Chapter 9 . If you want to exit Visual Studio 2010 now On the File menu, click Exit . If you see a Save dialog box, click Yes and save the project . Chapter .8 .Quick .Reference To Do this Copy a value type variable Simply make the copy . Because the variable is a value type, you will have two copies of the same value . For example: Copy a reference type variable Declare a variable that can hold avalue type or the null value Pass an argument to a ref parameter int i = 42; int copyi = i; Simply make the copy . Because the variable is a reference type, you will have two references to the same object . For example: Circle c = new Circle(42); Circle refc = c; Declare the variable using the ? modifier with the type . For example: int? i = null; Prefix the argument with the ref keyword . This makes the parameter an alias for the actual argument rather than a copy of the argument . The method may change the value of the parameter, and this change is made to the actual argument rather than a local copy . For example: static void Main() { int arg = 42; DoWork(ref arg); Console.WriteLine(arg); } 172 Part II Understanding the C# Language To Pass an argument to an out parameter Box a value Unbox a value Cast an object safely Do this Prefix the argument with the out keyword . This makes the parameter an alias for the actual argument rather than a copy of the argument . The method must assign a value to the parameter, and this value is made to the actual argument . For example: static void Main() { int arg = 42; DoWork(out arg); Console.WriteLine(arg); } Initialize or assign a variable of type object to the value . For example: object o = 42; Cast the object reference that refers to the boxed value to the type of the value variable . For example: int i = (int)o; Use the is operator to test whether the cast is valid . For example: WrappedInt wi = new WrappedInt(); ... object o = wi; if (o is WrappedInt) { WrappedInt temp = (WrappedInt)o; ... } Alternatively, use the as operator to perform the cast, and test whether the result is null . For example: WrappedInt wi = new WrappedInt(); ... object o = wi; WrappedInt temp = o as WrappedInt; if (temp != null) ... Chapter 9 Enumerations and Structures After completing this chapter, you will be able to: Declare an enumeration type . Create and use an enumeration type . Declare a structure type . Create and use a structure type . Explain the differences in behavior between a structure and a class . In Chapter 8, “Understanding Values and References,” you learned about the two fundamental types that exist in Microsoft Visual C#: value types and reference types . A value type variable holds its value directly on the stack, whereas a reference type variable holds a reference to an object on the heap . In Chapter 7, “Creating and Managing Classes and Objects,” you learned how to create your own reference types by defining classes . In this chapter, you’ll learn how to create your own value types . C# supports two kinds of value types: enumerations and structures . We’ll look at each of them in turn . Working .with .Enumerations Suppose you want to represent the seasons of the year in a program . You could use the integers 0, 1, 2, and 3 to represent spring, summer, fall, and winter, respectively . This system would work, but it’s not very intuitive . If you used the integer value 0 in code, it wouldn’t be obvious that a particular 0 represented spring . It also wouldn’t be a very robust solution . For example, if you declare an int variable named season, there is nothing to stop you from as-signing it any legal integer value apart from 0, 1, 2, or 3 . C# offers a better solution . You can create an enumeration (sometimes called an enum type), whose values are limited to a set of symbolic names . Declaring an Enumeration You define an enumeration by using the enum keyword, followed by a set of symbols identifying the legal values that the type can have, enclosed between braces . Here’s how to . . 173 174 Part II Understanding the C# Language declare an enumeration named Season whose literal values are limited to the symbolic names Spring, Summer, Fall, and Winter: enum Season { Spring, Summer, Fall, Winter } Using an Enumeration After you have declared an enumeration, you can use it in exactly the same way as any other type . If the name of your enumeration is Season, you can create variables of type Season, fields of type Season, and parameters of type Season, as shown in this example: enum Season { Spring, Summer, Fall, Winter } class Example { public void Method(Season parameter) { Season localVariable; ... } private Season currentSeason; } Before you can read the value of an enumeration variable, it must be assigned a value . Youcan assign a value that is defined by the enumeration only to an enumeration variable . For example: Season colorful = Season.Fall; Console.WriteLine(colorful); // writes out `Fall` Note As you can with all value types, you can create a nullable version of an enumeration variable by using the ? modifier . You can then assign the null value, as well the values defined by the enumeration, to the variable: Season? colorful = null; Notice that you have to write Season.Fall rather than just Fall . All enumeration literal names are scoped by their enumeration type . This is useful because it allows different enumerations to coincidentally contain literals with the same name . Also, notice that when you display an enumeration variable by using Console.WriteLine, the compiler generates code that writes out the name of the literal whose value matches the value of the variable . If needed, you can explicitly convert an enumeration variable to a string ... - tailieumienphi.vn