Why does the compiler when using an overload in another assembly sometimes require you to also reference a subassembly?
Asked Answered
M

0

6

There are quite a few questions/answers about the compiler error mentionend below and how to resolve it, but the question here is asking about some insights why in this case this is required.

Why does a project A which uses an overload of a method of another referenced project B, which uses an object of project C in one of it's overloaded signatures require, that you reference project C from project A, even if you never use the object from project C?

I guess it must have to do with the resolving of which overload to use, but I'd like to understand the concept behind.

Here's an example:

Put each of the classes in an own assembly.

//Put into Assembly C
public class C {}

//Put into assembly B, reference C
public class B
{
    public static void Test(string param) //Simple method with one string parameter
    {
    }

    public static void Test(C param) //Overload which uses type of assembly C   
    {
    }
}

//Call placed in method of assembly A which uses and references only assembly B, but not C
B.Test("TestString"); // fails to compile, CS0012

CS0012 The type 'C' is defined in an assembly that is not referenced. You must add a reference to assembly 'C, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

You can get interesting results when playing around with the overloads of assembly B, because not every combination does produce the error:

public static void Test(){}
public static void Test(C param){}

B.Test(); //Call from assembly A compiles


Another example:

public static void Test(string param){}
public static void Test(C param, int param2){}

B.Test(""); //Call from assembly A compiles


Yet another example:

public static void Test(string param, string param2){}
public static void Test(C param, int param2){}

B.Test("",""); //Fails, CS0012

So this propably has to do how the overload resolution is done. However, I don't understand why the compiler can't just work it's way up the dependency tree and requires me to do a direct reference? Wouldn't the overload resolution have to be done in assembly B anyways?

Ming answered 20/11, 2015 at 17:14 Comment(4)
Out of curiosity, and I don't have the chance to test this right now, but if you make C sealed do you still get the error? (public sealed class C {}) Check making B sealed too. I know a lot of logic changes once you introduce sealed classes because the compiler is allowed to make more assumptions about what the object you are working with is not.Alvinia
It happens when you expose types from the sub-assembly in the metadata of your primary assembly. Like you did by making C the type of the argument. The compiler decides that it needs to know more about C to decide which overload is correct. It used to be more lax about it, not exactly sure what changed. Probably some kind of nasty corner-case, overload resolution is forever convoluted.Anon
@ScottChamberlain it did not change the behaviour by making the class sealed.Ming
@HansPassant it seems that as soon as the number of parameters of a used overload is equal, the compiler wants to have the reference. I couldn't find the chapter in the c# documentation which describes this behaviour.Ming

© 2022 - 2024 — McMap. All rights reserved.