Do interface variables have value-type or reference-type semantics?
Interfaces are implemented by types, and those types are either value types or reference types. Obvi
A variable or field whose type is IComparable
is a reference-type variable or field, regardless of the type of the value assigned to that field. This means that x
in the sample code is boxed.
A simple test will demonstrate that. The test is based on the fact that you can only unbox a value type to its original type (and the nullable version of that type):
[TestMethod, ExpectedException(typeof(InvalidCastException))]
public void BoxingTest()
{
IComparable i = 42;
byte b = (byte)i; //exception: not allowed to unbox an int to any type other than int
Assert.AreEqual(42, b);
Assert.Fail();
}
EDIT
On top of that, the C# specification specifically defines reference-type as comprising class types, interface types, array types and delegate types.
EDIT 2
As Marc Gravell points out in his answer, a generic type with an interface constraint is a different case. This doesn't cause boxing.
Variables of interface type will have always have either immutable semantics, mutable reference semantics, or "oddball" semantics (something other than normal reference or value semantics). If variable1
and variable2
are both declared as the same interface type, one performs variable2 = variable1
, and one never again writes to either variable, the instance referred to by variable1
will always be indistinguishable from the one referred to be variable2
(since it will be the same instance).
Generic types with interface constraints may have immutable semantics, mutable reference semantics, or "quirky" semantics, but may also have mutable value semantics. This can be dangerous if the interface is not documented as having mutable value semantics. Unfortunately, there is no way to constrain an interface to have either immutable semantics or mutable value semantics (meaning that following variable2 = variable1
, it should not be possible to change variable1
by writing variable2
, nor vice versa). One could add a "struct" constraint along with the interface constraint, but that would exclude classes which have immutable semantics while not excluding structs that have reference semantics.
Usually, as per the existing answers, it is a reference-type and requires boxing; there is an exception though (isn't there always?). In a generic method with a where
constraint, it can be both:
void Foo<T>(T obj) where T : ISomeInterface {
obj.SomeMethod();
}
This is a constrained operation, and is not boxed even if it is a value-type. This is achieved via constrained. Instead, the JIT performs the operation as virtual-call for reference-types, and static-call for value-types. No boxing.
This is about understanding boxing and unboxing of types. In your example, the int is boxed upon assignment and a reference to that "box" or object is what is assigned to x. The value type int is defined as a struct which implements IComparable. However, once you use that interface reference to refer to the value type int, it will be boxed and placed on the heap. That's how it works in practice. The fact that using an interface reference causes boxing to occur by definition makes this reference type semantics.
MSDN: Boxing and Unboxing