I apologize, the section I was refering to in the current C# specification
is 14.4.2 Overload Resolution. I recommend you
read that section.
If you try compiling your example with the SSCLI (Rotor) implementation you
get the same error. Looking at the source code
for the compiler, it looks like the function verifyMethodCall gathers the
best methods by number of arguments and then
confirms if the given arguments types are convertible to the method's types.
If it passess then it puts the method on a
"best method" list. If the best list has more than one method it then goes
on to the more complicated best fit by
conversion logic.
In your example it looks like when the number of arguments don't conflict
all is well because it finds the one with the
string. But when it finds the TransactionHandler constructor which matches
the number of arguments, it checks to see if
the conversion is possible and thats when the compiler needs the type and
complains.
Mono on the other hand can resolve the string, it also finds the constructor
with TransactionHandler but because it
doesn't know anything about that type chooses to ignore it as a possible
best fit and chooses the string constructor.
So it looks like MS implementation is find all the methods with the same
number of arguments and then decide by type
conversion. Mono implementation is find all the methods with the same number
of arguments excluding those whose type is
unknown, then decide by type conversion. Reading the C# specification, it
says first find all applicable methods by number
of arguments then apply best fit by type. My view is that MS is doing the
right thing or at least the behavior is "intentional"
and can be explained, whether its a bug or not, I don't think so, but I'm
sure it all can be read different ways.
Just for kicks here is another test that I did to see what happens with a
different inheritence chain. The results were
the same, mono compiles (and ran) and MS doesn't compile.
Base.dll
public class Base {
}
Derived1.dll
//references Base.dll
public class Derived1:Base {
}
Derived2.dll
//references Base.dll
public class Derived2:Base {
}
Intermediate.dll
//references Base.dll and Derived2.dll
public class Intermediate {
public Intermediate(Base B){
Derived2 D2 = B as Derived2;
}
public Intermediate(Derived2 D2){
}
}
Final.dll
//references BAse.dll and Derived1.dll and Intermediate.dll
public class Final {
public Final(){
Intermediate I = new Intermediate(new Derived1());
}
public static void Main()
{
Final F = new Final();
System.Console.Write("went well");
}
}
"Martin Oddman" <sp**@me.not> wrote in message
news:%2***************@TK2MSFTNGP11.phx.gbl...
LOL, it does compile in MONO but not in Microsofts own compiler.
Nice work Microsoft!!!
Delenda est Microsoft
/martin...
Martin Oddman wrote:
I have made some research on this and found out an obvious bug in
the compiler.
If you have one internal constructor and one public constructor with
the same number of arguments and the internal constructor have an
argument with a reference to a class that shall not be accessible
for classes that calls the public constructor then you get this
error.
I hadn't noticed that in my first mail so my first example wasn't
100% correct. Here is an exact exempel how to reproduce it:
/************************************************** *****************/
/*** Create a project called Foo.Datamanager. ***/
/*** Create a file in that project named TransactionHandler.cs ***/
/*** and paste this code into that file. ***/
/************************************************** *****************/
namespace Foo.DataManager {
public class TransactionHandler {
public TransactionHandler(){
}
}
}
/************************************************** *****************/
/*** Create a project called Foo.Kernel. ***/
/*** Create a file in that project named CategoryItem.cs ***/
/*** and paste this code into that file. ***/
/*** Then make a reference from this project to Foo.Datamanager. ***/
/************************************************** *****************/
using Foo.DataManager;
namespace Foo.Kernel {
public class CategoryItem {
public CategoryItem(){
}
public CategoryItem(string s){
}
internal CategoryItem(TransactionHandler transaction) {
}
}
}
/************************************************** *****************/
/*** Create a project called Foo.UserInterface. ***/
/*** Create a file in that project named UserInterface.cs ***/
/*** and paste this code into that file. ***/
/*** Then make a reference from this project to Foo.Kernel. ***/
/************************************************** *****************/
using Foo.Kernel;
namespace Foo.UserInterface {
public class GUI {
public void AddItem(){
CategoryItem category = new CategoryItem(s); }
}
}
/************************************************** *****************/
/************************************************** *****************/
/************************************************** *****************/
If I remove either the middle constructor or the last constructor in
CategoryItem it works.
If I put an extra dummy argument on the internal constructor, so the
internal and public constructor get different number of arguments it
also works.
And one other funny thing is that it also works as long as you just
use the default constructor and not the CategoryItem(s) constructor
from the UserInterface class...
But as soon as the public and the internal constructors has the same
numbers of arguments I get this error message when trying to compile:
error CS0012: The type 'Foo.DataManager.TransactionHandler' is
defined in an assembly that is not referenced. You must add a
reference to assembly 'Foo.DataManager'.
It doesn't even matter what type the argument of the public
constructor has.
I can't see this is anything than a bug in the compiler.
/Martin