Unlicensed-645-648_7-PDF_C# Programming Language, The, 4th

advertisement
12.1
Array Types
12.1.2 Arrays and the Generic IList Interface
A one-dimensional array T[] implements the interface System.Collections.Generic.
IList<T> (IList<T> for short) and its base interfaces. Accordingly, there is an implicit
conversion from T[] to IList<T> and its base interfaces. In addition, if there is an
implicit reference conversion from S to T, then S[] implements IList<T> and there is
an implicit reference conversion from S[] to IList<T> and its base interfaces (§6.1.6). If
there is an explicit reference conversion from S to T, then there is an explicit reference
conversion from S[] to IList<T> and its base interfaces (§6.2.4). For example:
using System.Collections.Generic;
class Test
{
static void Main() {
string[] sa = new string[5];
object[] oa1 = new object[5];
object[] oa2 = sa;
IList<string>
IList<string>
IList<object>
IList<object>
lst1
lst2
lst3
lst4
=
=
=
=
sa;
oa1;
sa;
oa1;
//
//
//
//
IList<string> lst5 = (IList<string>)oa1;
IList<string> lst6 = (IList<string>)oa2;
Okay
Error: cast needed
Okay
Okay
// Exception
// Okay
}
}
The assignment lst2 = oa1 generates a compile-time error since the conversion from
object[] to IList<string> is an explicit conversion, not implicit. The cast (IList<string>)
oa1 will cause an exception to be thrown at runtime since oa1 references an object[] and
not a string[]. However, the cast (IList<string>)oa2 will not cause an exception to be
thrown since oa2 references a string[].
Whenever there is an implicit or explicit reference conversion from S[] to IList<T>, there
is also an explicit reference conversion from IList<T> and its base interfaces to S[]
(§6.2.4).
When an array type S[] implements IList<T>, some of the members of the implemented
interface may throw exceptions. The precise behavior of the implementation of the interface is beyond the scope of this specification.
n
n
ERIC LIPPERT
It's interesting to consider the counterfactual world in which the
CLR had generic types in version 1. In that counterfactual world, there would probably be generic array types Array<T>, Array2<T>, and so on. In this world, declarations
of complicated array types become more clear: An Array<Array2<int>> is a onedimensional array where every element is a two-dimensional array of integers.
627
www.it-ebooks.info
12.
Arrays
n
n
BILL WAGNER
The fact that an array T[] implements the IList<T> by throwing
exceptions for some methods is one of those troubling real-world problems for which
there isn't a good solution. IList<T> has methods that add or remove elements. Arrays
have a fixed size, however, and cannot support some of those methods. Even so, you
want to use the random access to elements that exists in the IList<T> interface.
12.2 Array Creation
ays
Array instances are created by array-creation-expressions (§7.6.10.4) or by field or local variable declarations that include an array-initializer (§12.6).
When an array instance is created, the rank and length of each dimension are established
and then remain constant for the entire lifetime of the instance. In other words, it is not
possible to change the rank of an existing array instance, nor is it possible to resize its
dimensions.
Arr
An array instance is always of an array type. The System.Array type is an abstract type that
cannot be instantiated.
12.
Elements of arrays created by array-creation-expressions are always initialized to their default
values (§5.2).
12.3 Array Element Access
Arr ays
Array elements are accessed using element-access expressions (§7.6.6.1) of the form A[I 1, I 2,
..., I N], where A is an expression of an array type and each I X is an expression of type int,
uint, long, or ulong, or can be implicitly converted to one or more of these types. The result
of an array element access is a variable—namely, the array element selected by the
indices.
12.
The elements of an array can be enumerated using a foreach statement (§8.8.4).
12.4 Array Members
Every array type inherits the members declared by the System.Array type.
628
www.it-ebooks.info
12.5
Covariance
Array
12.5 Array Covariance
For any two reference-types A and B, if an implicit reference conversion (§6.1.6) or explicit
reference conversion (§6.2.4) exists from A to B, then the same reference conversion also
exists from the array type A[R] to the array type B[R], where R is any given rank-specifier
(but the same for both array types). This relationship is known as array covariance. Array
covariance, in particular, means that a value of an array type A[R] may actually be a reference to an instance of an array type B[R], provided an implicit reference conversion exists
from B to A.
Because of array covariance, assignments to elements of reference type arrays include a
runtime check that ensures the value being assigned to the array element is actually of
a permitted type (§7.17.1). For example:
class Test
{
static void Fill(object[] array, int index, int count, object value) {
for (int i = index; i < index + count; i++)
array[i] = value;
}
static void Main() {
string[] strings = new string[100];
Fill(strings, 0, 100, "Undefined");
Fill(strings, 0, 10, null);
Fill(strings, 90, 10, 0);
}
}
The assignment to array[i] in the Fill method implicitly includes a runtime check that
ensures the object referenced by value is either null or an instance that is compatible with
the actual element type of array. In Main, the first two invocations of Fill succeed, but the
third invocation causes a System.ArrayTypeMismatchException to be thrown upon executing the first assignment to array[i]. The exception occurs because a boxed int cannot be
stored in a string array.
n
n
ERIC LIPPERT
This is my candidate for "worst feature" of C#. It allows assignments to fail at runtime without any indication in the source code that such failure is
possible. It imposes a performance cost on extremely common code to make a rare
scenario go quickly; accessing an array of unsealed reference type safely happens
much more often than covariant array conversions do. I much prefer the type-safe
covariance that has been added to IEnumerable<T>.
629
www.it-ebooks.info
12.
Arrays
n
n
CHRIS SELLS
I find myself using arrays so seldomly—even single-dimensional
arrays, let alone multi-dimensional or jagged arrays—that the strange corner cases
don't tend to matter much. Given the availability of List<T>, Dictionary<K, V>, and
IEnumerable<T>, I'd be a happy guy without arrays at all.
n
n
PETER SESToFT
The necessity for the runtime check that Eric laments stems
Arr ays
from the array type being covariant in the element type ( Student[] being a subtype of
Person[] when Student is a subtype of Person). This array covariance design weakness is shared with the Java programming language, where the situation is even worse:
Because Java implements generics by erasure, there is no type object representing a
generic type parameter at runtime, so the check cannot be performed if the array was
created as new T[...] for some type parameter T, or as new Stack<Person>[...].
Hence Java must forbid the creation of an array whose element type is a type parameter or a type constructed as a type instance of a generic type. In C#, type parameters
and constructed types are represented faithfully at runtime, so these restrictions on
array creation do not exist.
In the Scala language, which was born with generic types, the array type is invariant
in the element type and the runtime check is not needed (but is likely to be performed
anyway, when Scala is compiled to Java bytecode).
n
Arr ays
BILL WAGNER
Eric's comments go a long way toward explaining why the safe
n
covariance and contravariance added for generics in C# 4.0 are so important. Improving both speed and correctness with the same change is generally rare.
Array covariance specifically does not extend to arrays of value-types. For example, no
12.
conversion exists that permits an int[] to be treated as an object[].
12.6 Array Initializers
Array initializers may be specified in field declarations (§10.5), local variable declarations
(§8.5.1), and array creation expressions (§7.6.10.4):
{
{
12.
array-initializer:
variable-initializer-listopt
variable-initializer-list ,
}
}
630
www.it-ebooks.info
Download