
Bug in C# run-time type information?
Jan,
Quote:
>As proven by my example code this is not always the "complete truth".
It is, from the runtime's perspective.
Quote:
>Can you explain its behaviour?
I'll try :-) The weird results you see is caused by what I guess you
can call a bug in the C# compiler. It apparently doesn't properly
differentiate between types with the same name in different
assemblies.
First of all, I got the impression that you were using VS.NET. If you
are, use the command line compiler instead here. It makes it easier to
see what's going on.
When you compile assembly1 and assembly2, you should get a warning
CS0183 telling you that arg in Test1 will always be Common.Base, and
therefore using the as operator on it doesn't make much sense.
This is an important warning. If you look at the generated code in
ILDASM you'll see that an actual type test (the isinst instruction)
never happens. The compiler considered it unnecessary, and instead it
just tests if the argument is null or not. This is why the first line
of the output will always print "is a", unless you pass in null.
When you compile the test app, the output you get will depend on the
order in which you reference the assemblies. If you do
csc /r:assembly1.dll,assembly2.dll /out:test1.exe AssemblyTest.cs
The output is
Assembly2.Derived2 is a Common.Base in Assembly1.Derived1
Assembly2.Derived2 is not a Common.Base in Assembly1.Derived1
But if you reverse the order to
csc /r:assembly2.dll,assembly1.dll /out:test2.exe AssemblyTest.cs
you get
Assembly2.Derived2 is a Common.Base in Assembly1.Derived1
Assembly2.Derived2 is a Common.Base in Assembly1.Derived1
It turns out that the methods called in AssemblyTest.Main will be to
the first assembly referenced. In more ILAsm style syntax, you're
calling
[assembly1]Common.Base::Test1(class [assembly1]Common.Base)
[assembly1]Common.Base::Test2(object)
in the first case, and
[assembly2]Common.Base::Test1(class [assembly2]Common.Base)
[assembly2]Common.Base::Test2(object)
in the second.
So the second line of the output is actually correct. This is because,
if you look at the ILAsm code for Test2, it actually performs an
isinst check.
The error the C# compiler does is that it even allows you to call
Test1/Test2 in assembly1 and pass in a Base reference from assembly2.
It should catch this at compile time, but instead it produces
incorrect code. Try running PEVerify on the test executable and see it
complain.
Mattias
===
Mattias Sj?gren (VB MVP)