Herfried said:
You snipped the code sample.
Why is the 'BaseType' property 'null' for interfaces in C# too? Why does this property behave differently from its
documentation?
Interesting. Your are right: GetType(I).BaseType returns a null reference
in both languages. (Considering that both languages call into the same
library, it's not surprising that the result is the same in both languages.)
But the result itself is surprising.
So, I did a bit more digging and found a few interesting snippets.
- From the C# language spec:
"For purposes of member lookup, a type T is considered to have the following base types:
[...]
- If T is an interface-type, the base types of T are the base interfaces of T
and the class type object.
- If I write
interface I {}
// ...
Type t = typeof(I);
MethodInfo[] mi = t.GetMethods(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.FlattenHierarchy |
BindingFlags.Static);
The returned method array is empty. This is in direct conflict with what is stated in the spec.
- I can write
iref.Equals(null)
and the compiler is perfectly happy to let me do that. In other words, the compiler
allows access to methods on System.Object via an interface reference, and those methods
do exactly what you'd expect them to do, yet reflection claims that those methods do not
exist.
- If I write
I iref = null;
Console.WriteLine(iref is object);
The compiler omits the following warning:
warning CS0183: The given expression is always of the provided ('object') type
The warning is in agreement with the language specification.
However, when I run that program, it prints false! In other words, the compiler says
that iref "is-a" object, but reflection says iref "is-not-a" object. That's rather sick...
Going through this exercise in VB, we get:
- GetMethods() does not return the methods on Object. Considering that both languages use
the same reflection library, that's not really a surprise.
- If I write
Dim iref As I = Nothing
Console.WriteLine(TypeOf iref Is Object)
the output is "False", which is in accordance with the compiler's idea that interface
types do not inherit from Object.
So, in summary, here is what I can see:
- The C# compiler implements the behavior of the C# language specification, but the
behavior of reflection at run time is in conflict with that specification.
- The VB compiler disagrees with its own language specification, as does the behavior
of reflection at run time.
- The VB compiler is schizophrenic: it allows me to write oref = iref (permitting an
implicit widening from an interface type to Object), but it doesn't allow me to
write iref.Equals(). In other words, the compiler applies implicit widening
in one situation, but not in the other. The compiler should at least be consistent.
Now, what would happen if that were fixed? I see two issues:
Issue 1: What happens if VB is changed to permit the expression iref.Equals(...)?
I don't see a problem here:
All VB programs that currently invoke a method on Object via an interface reference
can do so only by either using an explicit cast (CType) to Object, or by assigning
(or passing) the interface reference to an object reference. If the change is
existing programs will continue to work exactly as they do now.
Semantically, it makes sense to allow access to the methods on Object via an interface
reference: at run time, an interface reference can either be Nothing, or point at
an instance. Anything that is instantiated does indeed provide the methods on Object,
so it cannot happen that the compiler would permit a method call to an object that, at
run time, does not provide the method (i.e., the Smalltalk behavior of calling a
non-existent method at run time cannot arise).
Issue 2: What happens if System.Reflection is changed to return the methods on Object
for a reference to an interface?
That one is more hairy, because it is difficult to see the ramifications. It may well
be that existing code gets unpleasant surprises.
Note that the alternative of changing C# to behave like VB is not viable, because that
would definitely break a lot of existing code.
Cheers,
Michi.