Re: Internal constructor "visible" outside of assembly. (BUG IN COMPILER CONFIRMED, EXACT CODEEXAMPLE TO REPRODUCE INCLUDED)

From: JD (no_at_address.org)
Date: 08/12/04


Date: Thu, 12 Aug 2004 14:52:27 -0400

In V1.1 C# compiler (not using visual studio just using csc) I did get the
same result as Martin, but I'm not so sure if its a bug or not.

>From the C# spec:

<snip>
7.4.2 Overload Resolution
Overload resolution is a compile-time mechanism... (which is clear)
    :
    :
Once the candidate function members and the argument list have been
identified, the selection of the best function member is the same in all
cases.

Given the set of applicable candidate function members, the best function
member in that set is located. If the set contains only one function member,
then that function member is the best function member. Otherwise, the best
function member is the one function member that is better than all other
function members with respect to the given argument list, provided that each
function member is compared to all other function members using the rules in
§7.4.2.2.

7.4.2.2 Better Function Member
Given an argument list A with a set of argument types { A1, A2, ..., AN }
and two applicable function members MP and MQ with parameter types { P1, P2,
..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function
member than MQ if

For each argument, the implicit conversion from AX to PX is not worse than
the implicit conversion from AX to QX, and

For at least one argument, the conversion from AX to PX is better than the
conversion from AX to QX.

When performing this evaluation, if MP or MQ is applicable in its expanded
form, then PX or QX refers to a parameter in the expanded form of the
parameter list.

</snip>

I believe that private/internal does not influence overloading
determination. If this is true then the only way the compiler knows how to
resolve the two constructors is by going through the logic in 7.4.2.2 above.
How would the compiler run through the logic in 7.4.2.2 without knowing what
the TransactionHandler type is? I'm no compiler expert but this problem just
had me thinking. And maybe Mono isn't as strict as it should be.

JD

"Martin Oddman" <spam@me.not> wrote in message
news:%23BYjkKIgEHA.596@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
> >
> >



Relevant Pages


Loading