Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 185 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
185
Dung lượng
676,64 KB
Nội dung
Chapter 5: Arrays 125 Multidimensional Arrays Ordinary arrays (also known as 1 - dimensional arrays) are indexed by a single integer. A multidimensional array is indexed by two or more integers. Figure 5 - 3 shows the mathematical notation for a 2 - dimensional array that has three rows and three columns. The first row has the values 1, 2, and 3, and the third row has the values 7, 8, and 9. 1, 2, 3 4, 5, 6 7, 8, 9 a ϭ Figure 5 - 3 Declaring this 2 - dimensional array with C# is done by putting a comma inside the brackets. The array is initialized by specifying the size of every dimension (also known as rank). Then the array elements can be accessed by using two integers with the indexer: int[,] twodim = new int[3, 3]; twodim[0, 0] = 1; twodim[0, 1] = 2; twodim[0, 2] = 3; twodim[1, 0] = 4; twodim[1, 1] = 5; twodim[1, 2] = 6; twodim[2, 0] = 7; twodim[2, 1] = 8; twodim[2, 2] = 9; You cannot change the rank after declaring an array. You can also initialize the 2 - dimensional array by using an array indexer if you know the value for the elements in advance. For the initialization of the array, one outer curly bracket is used, and every row is initialized by using curly brackets inside the outer curly brackets. int[,] twodim = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; When using an array initializer, you must initialize every element of the array. It is not possible to leave the initialization for some values. By using two commas inside the brackets, you can declare a 3 - dimensional array: int[,,] threedim = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } }, { { 9, 10 }, { 11, 12 } } }; Console.WriteLine(threedim[0, 1, 1]); c05.indd 125c05.indd 125 2/19/08 5:01:49 PM2/19/08 5:01:49 PM Part I: The C# Language 126 Jagged Arrays A 2 - dimensional array has a rectangular size (for example, 3 × 3 elements). A jagged array is more flexible in sizing the array. With a jagged array every row can have a different size. Figure 5 - 4 contrasts a 2 - dimensional array that has 3 × 3 elements with a jagged array. The jagged array shown contains three rows where the first row has two elements, the second row has six elements, and the third row has three elements. Two-Dimensional Array Jagged Array 12 12 3 456 7 8 9 10 11 3 456 789 Figure 5 - 4 A jagged array is declared by placing one pair of opening and closing brackets after another. With the initialization of the jagged array, only the size that defines the number of rows in the first pair of brackets is set. The second brackets that define the number of elements inside the row are kept empty because every row has a different number of elements. Next, the element number of the rows can be set for every row: int[][] jagged = new int[3][]; jagged[0] = new int[2] { 1, 2 }; jagged[1] = new int[6] { 3, 4, 5, 6, 7, 8 }; jagged[2] = new int[3] { 9, 10, 11 }; Iterating through all elements of a jagged array can be done with nested for loops. In the outer for loop every row is iterated, and the inner for loop iterates through every element inside a row. for (int row = 0; row < jagged.Length; row++) { for (int element = 0; element < jagged[row].Length; element++) { Console.WriteLine( “row: {0}, element: {1}, value: {2}”, row, element, jagged[row][element]); } } The outcome of the iteration displays the rows and every element within the rows: row: 0, element: 0, value: 1 row: 0, element: 1, value: 2 row: 1, element: 0, value: 3 row: 1, element: 1, value: 4 row: 1, element: 2, value: 5 row: 1, element: 3, value: 6 row: 1, element: 4, value: 7 row: 1, element: 5, value: 8 row: 2, element: 1, value: 9 row: 2, element: 2, value: 10 row: 2, element: 3, value: 11 c05.indd 126c05.indd 126 2/19/08 5:01:49 PM2/19/08 5:01:49 PM Chapter 5: Arrays 127 Array Class Declaring an array with brackets is a C# notation of using the Array class. Using the C# syntax behind the scenes creates a new class that derives from the abstract base class Array . It is possible, in this way, to use methods and properties that are defined with the Array class with every C# array. For example, you ’ ve already used the Length property or iterated through the array by using the foreach statement. By doing this, you are using the GetEnumerator() method of the Array class. Properties The Array class contains the properties listed in the following table that you can use with every array instance. More properties are available, which are discussed later in this chapter. Property Description Length The Length property returns the number of elements inside the array. If the array is a multidimensional array, you get the number of elements of all ranks. If you need to know the number of elements within a dimension, you can use the GetLength() method instead. LongLength The Length property returns an int value; the LongLength property returns the length in a long value. If the array contains more elements than fit into a 32 - bit int value, you need to use the LongLength property to get the number of ele- ments. Rank With the Rank property you get the number of dimensions of the array. Creating Arrays The Array class is abstract, so you cannot create an array by using a constructor. However, instead of using the C# syntax to create array instances, it is also possible to create arrays by using the static CreateInstance() method. This is extremely useful if you don ’ t know the type of the elements in advance, because the type can be passed to the CreateInstance() method as a Type object. The following example shows how to create an array of type int with a size of 5. The first argument of the CreateInstance() method requires the type of the elements, and the second argument defines the size. You can set values with the SetValue() method, and read values with the GetValue() method. Array intArray1 = Array.CreateInstance(typeof(int), 5); for (int i = 0; i < 5; i++) { intArray1.SetValue(33, i); } for (int i = 0; i < 5; i++) { Console.WriteLine(intArray1.GetValue(i)); } You can also cast the created array to an array declared as int[] : int[] intArray2 = (int[])intArray1; c05.indd 127c05.indd 127 2/19/08 5:01:50 PM2/19/08 5:01:50 PM Part I: The C# Language 128 The CreateInstance() method has many overloads to create multidimensional arrays and also to create arrays that are not 0 - based. The following example creates a 2 - dimensional array with 2 × 3 elements. The first dimension is 1 - based; the second dimension is 10 - based. int[] lengths = { 2, 3 }; int[] lowerBounds = { 1, 10 }; Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds); Setting the elements of the array, the SetValue() method accepts indices for every dimension: racers.SetValue(new Person(“Alain”, “Prost”), 1, 10); racers.SetValue(new Person(“Emerson”, “Fittipaldi”), 1, 11); racers.SetValue(new Person(“Ayrton”, “Senna”), 1, 12); racers.SetValue(new Person(“Ralf”, “Schumacher”), 2, 10); racers.SetValue(new Person(“Fernando”, “Alonso”), 2, 11); racers.SetValue(new Person(“Jenson”, “Button”), 2, 12); Although the array is not 0 - based you can assign it to a variable with the normal C# notation. You just have to pay attention to not crossing the boundaries. Person[,] racers2 = (Person[,])racers; Person first = racers2[1, 10]; Person last = racers2[2, 12]; Copying Arrays Because arrays are reference types, assigning an array variable to another one just gives you two variables referencing the same array. For copying arrays, the array implements the interface ICloneable . The Clone() method that is defined with this interface creates a shallow copy of the array. If the elements of the array are value types, as in the following code segment, all values are copied, as you can see in Figure 5 - 5 . int[] intArray1 = {1, 2}; int[] intArray2 = (int[])intArray1.Clone(); intArray1 1 2 intArray2 1 2 Figure 5 - 5 If the array contains reference types, only the references are copied; not the elements. Figure 5 - 6 shows the variables beatles and beatlesClone , where beatlesClone is created by calling the Clone() method from beatles . The Person objects that are referenced are the same with beatles and beatlesClone . If you change a property of an element of beatlesClone , you change the same object of beatles . Person[] beatles = { new Person(“John”, “Lennon”), new Person(“Paul”, “McCartney”) }; Person[] beatlesClone = (Person[])beatles.Clone(); c05.indd 128c05.indd 128 2/19/08 5:01:50 PM2/19/08 5:01:50 PM Chapter 5: Arrays 129 Instead of using the Clone() method, you can use the Array.Copy() method, which creates a shallow copy as well. But there ’ s one important difference with Clone() and Copy() : Clone() creates a new array; with Copy() you have to pass an existing array with the same rank and enough elements. If you need a deep copy of an array containing reference types, you have to iterate the array and create new objects. Sorting The Array class implements a bubble - sort for sorting the elements in the array. The Sort() method requires the interface IComparable to be implemented by the elements in the array. Simple types such as System. String and System.Int32 implement IComparable , so you can sort elements containing these types. With the sample program, the array name contains elements of type string, and this array can be sorted: string[] names = { “Christina Aguilera”, “Shakira”, “Beyonce”, “Gwen Stefani” }; Array.Sort(names); foreach (string name in names) { Console.WriteLine(name); } The output of the application shows the sorted result of the array: Beyonce Christina Aguilera Gwen Stefani Shakira If you are using custom classes with the array, you must implement the interface IComparable . This interface defines just one method, CompareTo() , that must return 0 if the objects to compare are equal, a value smaller than 0 if the instance should go before the object from the parameter, and a value larger than 0 if the instance should go after the object from the parameter. Change the Person class to implement the interface IComparable . The comparison is done on the value of the LastName . Because the LastName is of type string , and the String class already implements the beatles Reference Person Reference beatlesClone Reference Person Reference Figure 5 - 6 c05.indd 129c05.indd 129 2/19/08 5:01:50 PM2/19/08 5:01:50 PM Part I: The C# Language 130 IComparable interface, with the implementation you can rely on the CompareTo() method of the String class. If the LastName has the same value, the FirstName is compared: public class Person : IComparable { public int CompareTo(object obj) { Person other = obj as Person; int result = this.LastName.CompareTo( other.LastName); if (result == 0) { result = this.FirstName.CompareTo( other.FirstName); } return result; } // Now it is possible to sort an array of Person objects by the last name: Person[] persons = { new Person(“Emerson”, “Fittipaldi”), new Person(“Niki”, “Lauda”), new Person(“Ayrton”, “Senna”), new Person(“Michael”, “Schumacher”) }; Array.Sort(persons); foreach (Person p in persons) { Console.WriteLine(p); } Using the sort of the Person class, the output returns the names sorted by the last name: Emerson Fittipaldi Niki Lauda Michael Schumacher Ayrton Senna If the Person object should be sorted differently, or if you don ’ t have the option to change the class that is used as an element in the array, you can implement the interface IComparer . This interface defines the method Compare() . The interface IComparable must be implemented by the class that should be compared. The IComparer interface is independent of the class to compare. That ’ s why the Compare() method defines two arguments that should be compared. The return value is similar to the CompareTo() method of the IComparable interface. The class PersonComparer implements the IComparer interface to sort Person objects either by firstName or by lastName . The enumeration PersonCompareType defines the different sorting options that are available with the PersonComparer : FirstName and LastName . How the compare should happen is defined with the constructor of the class PersonComparer where a PersonCompareType value is set. The Compare() method is implemented with a switch statement to compare either by LastName or by FirstName . c05.indd 130c05.indd 130 2/19/08 5:01:51 PM2/19/08 5:01:51 PM Chapter 5: Arrays 131 public class PersonComparer : IComparer { public enum PersonCompareType { FirstName, LastName } private PersonCompareType compareType; public PersonComparer( PersonCompareType compareType) { this.compareType = compareType; } public int Compare(object x, object y) { Person p1 = x as Person; Person p2 = y as Person; switch (compareType) { case PersonCompareType.FirstName: return p1.FirstName.CompareTo( p2.FirstName); case PersonCompareType.LastName: return p1.LastName.CompareTo( p2.LastName); default: throw new ArgumentException( “unexpected compare type”); } } } Now you can pass a PersonComparer object to the second argument of the Array.Sort() method. Here the persons are sorted by first name: Array.Sort(persons, new PersonComparer( PersonComparer.PersonCompareType. FirstName)); foreach (Person p in persons) { Console.WriteLine(p); } The persons array is now sorted by the first name: Ayrton Senna Emerson Fittipaldi Michael Schumacher Niki Lauda The Array class also offers Sort methods that require a delegate as an argument. Chapter 7 , “ Dele- gates and Events, ” discusses how to use delegates. c05.indd 131c05.indd 131 2/19/08 5:01:51 PM2/19/08 5:01:51 PM Part I: The C# Language 132 Array and Collection Interfaces The Array class implements the interfaces IEnumerable , ICollection , and IList for accessing and enumerating the elements of the array. Because with a custom array a class is created that derives from the abstract class Array , you can use the methods and properties of the implemented interfaces with an array variable. IEnumerable IEnumerable is an interface that is used by the foreach statement to iterate through the array. Because this is a very special feature, it is discussed in the next section, “ Enumerations. ” ICollection The interface ICollection derives from the interface IEnumerable and has additional properties and methods as shown in the following table. This interface is mainly used to get the number of elements in a collection and for synchronization. ICollection Interface Properties and Methods Description Count The Count property gives you the number of elements inside the collec- tion. The Count property returns the same value as the Length property. IsSynchronized SyncRoot The property IsSynchronized defines whether the collection is thread - safe. For arrays, this property always returns false . For synchronized access, the SyncRoot property can be used for thread - safe access. Chapter 19 , “ Threading and Synchronization, ” explains threads and synchronization, and there you can read how to implement thread safety with collections. CopyTo() With the CopyTo() method you can copy the elements of an array to an existing array. This is similar to the static method Array.Copy() . IList The IList interface derives from the interface ICollection and defines additional properties and methods. The major reason why the Array class implements the IList interface is that the IList interface defines the Item property for accessing the elements using an indexer. Many of the other IList members are implemented by the Array class by throwing a NotSupportedExceptio n , because these do not apply to arrays. All the properties and methods of the IList interface are shown in the following table. IList Interface Description Add() The Add() method is used to add elements to a collection. With arrays, the method throws a NotSupportedException . Clear() The Clear() method empties all elements of the array. Value types are set to 0 , reference types to null . c05.indd 132c05.indd 132 2/19/08 5:01:52 PM2/19/08 5:01:52 PM Chapter 5: Arrays 133 IList Interface Description Contains() With the Contains() method, you can find out if an element is within the array. The return value is true or false . This method does a linear search through all elements of the array until the element is found. IndexOf() The IndexOf() method does a linear search through all elements of the array similar to the Contains() method. What ’ s different is that the IndexOf() method returns the index of the first element found. Insert() Remove() RemoveAt() With collections, the Insert() method is used to insert elements; with Remove() and RemoveAt() , elements can be removed. With arrays, all these methods throw a NotSupportedException . IsFixedSize Because arrays are always fixed in size, this property always returns true . IsReadOnly Arrays are always read/write, so this property returns false . In Chapter 10 , “ Collections, ” you can read how to create a read - only collection from an array. Item The Item property allows accessing the array using an integer index. Enumerations By using the foreach statement you can iterate elements of a collection without the need to know the number of elements inside the collection. The foreach statement uses an enumerator. Figure 5 - 7 shows the relationship between the client invoking the foreach method and the collection. The array or collection implements the IEnumerable interface with the GetEnumerator() method. The GetEnumerator() method returns an enumerator implementing the IEnumerable interface. The interface IEnumerable then is used by the foreach statement to iterate through the collection. The GetEnumerator() method is defined with the interface IEnumerable . The foreach statement doesn ’ t really need this interface implemented in the collection class. It ’ s enough to have a method with the name GetEnumerator() that returns an object implementing the IEnumerator interface. Client Enumerator IEnumerator IEnumerable Collection Figure 5 - 7 c05.indd 133c05.indd 133 2/19/08 5:01:52 PM2/19/08 5:01:52 PM Part I: The C# Language 134 IEnumerator Interface The foreach statement uses the methods and properties of the IEnumerator interface to iterate all elements in a collection. The properties and methods from this interface are defined in the following table. IEnumerator Interface Properties and Methods Description MoveNext() The MoveNext() method moves to the next element of the collection and returns true if there ’ s an element. If the collection does not contain any more elements, the value false is returned. Current The property Current returns the element where the cursor is positioned. Reset() The method Reset() repositions the cursor to the beginning of the collection. Many enumerators throw a NotSupportedException . foreach Statement The C# foreach statement is not resolved to a foreach statement in the IL code. Instead, the C# compiler converts the foreach statement to methods and properties of the IEnumerable interface. Here ’ s a simple foreach statement to iterate all elements in the persons array and to display them person by person: foreach (Person p in persons) { Console.WriteLine(p); } The foreach statement is resolved to the following code segment. First, the GetEnumerator() method is invoked to get an enumerator for the array. Inside a while loop — as long as MoveNext() returns true — the elements of the array are accessed using the Current property: IEnumerator enumerator = persons.GetEnumerator(); while (enumerator.MoveNext()) { Person p = (Person)enumerator.Current; Console.WriteLine(p); } yield Statement C# 1.0 made it easy to iterate through collections by using the foreach statement. With C# 1.0, it was still a lot of work to create an enumerator. C# 2.0 adds the yield statement for creating enumerators easily. yield return returns one element of a collection and moves the position to the next element, and yield break stops the iteration. The next example shows the implementation of a simple collection using the yield return statement. The class HelloCollection contains the method GetEnumerator() . The implementation of c05.indd 134c05.indd 134 2/19/08 5:01:53 PM2/19/08 5:01:53 PM [...]... demonstrate arithmetic operations Vector vect1, vect2, vect3; vect1 = new Vector(1.0, 1.5, 2. 0); vect2 = new Vector(0.0, 0.0, -10.0); vect3 = vect1 + vect2; Console.WriteLine(“vect1 = Console.WriteLine(“vect2 = Console.WriteLine(“vect3 = Console.WriteLine( 2* vect3 “ + vect1); “ + vect2); vect1 + vect2 = “ + vect3); = “ + 2* vect3); 160 c06.indd 160 2/ 19/08 5: 02: 13 PM ... 158 c06.indd 158 2/ 19/08 5: 02: 13 PM Chapter 6: Operators and Casts Now all you need to do is write some simple code to test the Vector struct Here it is: static void Main() { Vector vect1, vect2, vect3; vect1 = new Vector(3.0, 3.0, 1.0); vect2 = new Vector (2. 0, -4.0, -4.0); vect3 = vect1 + vect2; Console.WriteLine(“vect1 = “ + vect1.ToString()); Console.WriteLine(“vect2 = “ + vect2.ToString()); Console.WriteLine(“vect3... vect1, vect2, vect3; // initialize vect1 and vect2 vect3 = vect1 + vect2; vect1 = vect1 *2; Here, Vector is the struct, which is defined in the following section The compiler will see that it needs to add two Vector instances, vect1 and vect2, together It will look for an overload of the addition operator, which takes two Vector instances as its parameters 156 c06.indd 156 2/ 19/08 5: 02: 12 PM Chapter... unsafe mode This is not a requirement since the NET Framework 2. 0 Category Operator Operator keywords sizeof (for NET Framework versions 1.0 and 1.1 only) Operators * -> & 1 42 c06.indd 1 42 2/19/08 5: 02: 07 PM Chapter 6: Operators and Casts One of the biggest pitfalls to watch out for when using C# operators is that, like other C-style languages, C# uses different operators for assignment (=) and comparison... seamless data type-conversions Operators Although most of C# s operators should be familiar to C and C++ developers, this section discusses the most important operators for the benefit of new programmers and Visual Basic converts, as well as to shed light on some of the changes introduced with C# c06.indd 141 2/ 19/08 5: 02: 06 PM Part I: The C# Language C# supports the operators listed in the following table... included in C#, allows you to avoid some of the most common situations in which you would need to perform type conversions See Chapter 9, “Generics,” for details 148 c06.indd 148 2/ 19/08 5: 02: 09 PM Chapter 6: Operators and Casts Type Conversions Often, you need to convert data from one type to another Consider the following code: byte value1 = 10; byte value2 = 23 ; byte total; total = value1 + value2; Console.WriteLine(total);... example, 2 * (1.0, 2. 5, 2. 0) returns (2. 0, 5.0, 4.0) The relevant operator overload looks like this: public static Vector operator * (double lhs, Vector rhs) { return new Vector(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); } This by itself, however, is not sufficient If a and b are declared as type Vector, it will allow you to write code like this: b = 2 * a; The compiler will implicitly convert the integer 2. .. The maximum int is 21 47483647 150 c06.indd 150 2/ 19/08 5: 02: 10 PM Chapter 6: Operators and Casts In this case, you will not get an error, but you also will not get the result you expect If you run this code and output the value stored in i, this is what you get: - 129 496 729 6 It is good practice to assume that an explicit cast will not give the results you expect As you saw earlier, C# provides a checked... linked lists 139 c05.indd 139 2/ 19/08 5:01:54 PM c05.indd 140 2/ 19/08 5:01:54 PM Operators and Casts The preceding chapters have covered most of what you need to start writing useful programs using C# This chapter completes the discussion of the essential language elements and begins to illustrate some powerful aspects of C# that allow you to extend the capabilities of the C# language Specifically, this... int 1 52 c06.indd 1 52 2/19/08 5: 02: 10 PM Chapter 6: Operators and Casts You can only unbox a variable that has previously been boxed If you execute the last line when myObject is not a boxed int, you will get an exception thrown at runtime One word of warning: when unboxing, you have to be careful that the receiving value variable has enough room to store all the bytes in the value being unboxed C# s . shed light on some of the changes introduced with C#. c06.indd 141c06.indd 141 2/ 19/08 5: 02: 06 PM2/19/08 5: 02: 06 PM 1 42 Part I: The C# Language C# supports the operators listed in the following. 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } }, { { 9, 10 }, { 11, 12 } } }; Console.WriteLine(threedim[0, 1, 1]); c05.indd 125 c05.indd 125 2/ 19/08 5:01:49 PM2/19/08 5:01:49 PM Part I: The C#. c05.indd 126 c05.indd 126 2/ 19/08 5:01:49 PM2/19/08 5:01:49 PM Chapter 5: Arrays 127 Array Class Declaring an array with brackets is a C# notation of using the Array class. Using the C# syntax