Why am I forced to reference types in unused constructors?
Asked Answered
G

3

6

Let's say that I have a class (ClassA) containing one method which calls the constructor of another class, like this:

public class ClassA
{
    public void CallClassBConstructor()
    {
        using(ClassB myB = new ClassB()) {...}
    }
}

The class ClassB looks like this:

public class ClassB : IDisposable
{
    public ClassB(){}
    public ClassB(string myString){}
    public ClassB(ClassC myC){}
    public void Dispose() {...}
}

...and ClassC is even more simple:

public class ClassC{}

If I put these classes in their own assembly and compile the whole solution I don't get any errors. But if I replace the using statement with this:

using(ClassB myB = new ClassB("mystring")){...}

I get a compile error asking me to add a reference to [mynamespace].ClassC in ClassA. Since I'm not calling ClassB(ClassC myC) at all this makes no sense to me - why do I have to include the types of other constructors regardless of whether I use them or not? What if ClassC was included in a licensed or hard-to-aquire assembly? Is this an example of bad design that developers should avoid or am I missing something here?

Got answered 2/9, 2010 at 11:27 Comment(0)
A
9

It has to do with method overload resolution when calling the ClassB constructor.

When you call the constructor with no parameters, there is no contention. There is only one candidate, so it is chosen. It is not necessary for ClassA to reference ClassC in this case.

However, when you call the constructor with one parameter, then at the outset both of the single-parameter constructors are candidates. In order to resolve this call, the compiler needs to know about ClassC. For all you know, ClassC could contain an implicit conversion operator, for example.

(Of course we know that in this particular example such an implicit conversion operator wouldn’t fire anyway because there is a perfect match that takes a string — but the method overload resolution rules are defined this way to make them very well-defined and predictable. Imagine it were designed in such a way that adding a reference could cause your code to suddenly call a different constructor overload.)

Alienism answered 2/9, 2010 at 11:47 Comment(3)
How come a missing using statement is not enough for the compiler to know which overload to use? I'm confused that simply adding the reference makes the compiler happy.Cahra
@Stijn: You probably mean the using directive, not the using statement. But even so, neither the question nor my answer have anything to do with using statements or using directives. They are about references to other assemblies. The using declaration does not add such a reference.Alienism
Indeed I meant the using directive. I do believe OP and me had the same problem though. I had to add a reference to an assembly for a constructor overload that I'm not using. And now I was wondering why it doesn't know that I don't want to use that specific overload, when the required using to gain access to the class used in the overload is missing. Perhaps I should open a new question?Cahra
S
1

To resolve the constructor overloads, the compiler needs to know the types involved. I.e. it needs to know ClassC in order to pick the right constructor overload for ClassB.

Schorl answered 2/9, 2010 at 11:45 Comment(0)
F
1

It is because ClassC, which you have placed in a separate assembly, is part of the public interface of ClassB since it is a parameter of one of the constructors. You must reference the containing assembly of this type otherwise the compiler has no idea how to resolve the type information. In this specific case the compiler must resolve all parameter types from all constructor overloads so that it can choose the right one, but this is not a member overloading issue per se. This happens anytime the compiler must resolve type information. It can happen on return types as well.

Formaldehyde answered 2/9, 2010 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.