Assignment Compatibility
As the concepts of object types and interface types have now been explained, albeit very simply, the question of assignment compatibility can be addressed. A simple definition of assignment compatibility for reference types is that a location of type T, where T may be either an object type or an interface type, can refer to any object:
With an exact type of T, or
That is a subtype of T, or
That supports the interface T.
Listing 2.10 demonstrates aspects of assignment compatibility. The program starts by creating values of two different types and two interface references:
A value of type System.Int32 called i
An Object reference called o
A String reference called s
An IComparable reference called ic
Listing 2.10 Assignment compatibility
using System; namespace AssignmentCompatibility { class Sample { static void Main(string[] args) { System.Int32 i = 42; Object o; String s = "Brad"; IComparable ic; // OK o = s; ic = s; // OK - box and assign o = i; ic = i; // compiler error i = s; // runtime error s = (String) o; } } }
The assignments of s to o and of s to ic are all compatible, so they compile and execute without any errors. The next two assignments are also compatible, so they, too, compile and execute without any errors. The surprise may come with the fact that boxing of i is needed, which the C# compiler performs silently in both cases. Other languages might require explicit code to handle this boxing.
The assignment of s to i is not compatible, so it generates a compile-time error. Unfortunately, downcasting (narrowing) is inherently problematic, making the last assignment difficult to test for compatibility until runtime. The JIT compiler will insert code to check the type of the object referenced by o before performing the assignment. In this case, o refers to a boxed integer type at the time of assignment, so the cast fails and an exception is thrown. Of course, if o did refer to a string, then the cast would execute without throwing an exception.
Assignment compatibility is a crucial mechanism that helps ensure type safety in the CLR. The execution system can validate assignment to a reference to verify that the assignment ensures that the type and the reference are compatible.