C# 4.0 Compile time error, fails to resolve overload when wrong overload contains parameter types defined in .NET components that are not referenced [closed]
Asked Answered
N

1

6

Here's simple code for a C# 4.0 console program:

using System.DirectoryServices.Protocols;
namespace OverloadTest
{
  class Program
  {
    static void Main(string[] args)
    {
      var request = new SearchRequest("", "", SearchScope.Base, null);
    }
  }
}

SearchRequest has 3 constructors; only the two which take 4 parameters matter for this example:

Between these two constructors, they have identically typed and named parameters for their first, third and forth parameters. Only the second parameters differ: string ldapFilter versus XmlDocument filter.

The above code is, obviously-to-me, calling the constructor which has its second parameter declared as: string ldapFilter.

But if the project that this code is in does NOT have a reference to System.XML then a compile results in the following error:
The type 'System.Xml.XmlDocument' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

Apparently the compiler can't evaluate which overload to use because the wrong overload has a parameter of a type that is not understood due to the lack of reference to the declaring component. Sure, the compiler has to find a 'best method' to match my code, but as my second passed parameter is a string why does the compiler need to bother worrying about matching my code to the XmlDocument overload? Or alternatively, as System.DirectoryServices.Protocols.SearchRequest is using the XmlDocument type (as a constructor parameter type); why doesn't the compiler already know enough enough about what an XmlDocument is to determine that a string is not one and thus be able to choose the correct overload?

I've already got two work-arounds that compile without error:

  1. Add a reference to System.XML in the project.

  2. Name the 2nd parameter (and thus the 3rd and 4th too by necessity), like so:

    var request = new SearchRequest("", ldapFilter: "", searchScope: SearchScope.Base, attributeList: null);
    

    For my particular case, this works because the two overloads' second parameters differ not just in type but also in name (ldapFilter versus filter).

It'd be nice though if neither work-around was needed.

Nananne answered 16/2, 2012 at 1:17 Comment(4)
Although interesting, I'm voting to close because this seems like little more than a complaint about the nature of dependency resolution.Invective
Interesting found. I think compiler has to know the type information of parameters of all overload methods to resolve which one is the best.Enunciate
Nothing quite keeps a compiler writer up at night as unintended method overload resolution. This example is at the bottom of the pile.Osy
+1 Interesting and indeed a valid questionApuleius
T
3

The second overload might still be applicable, due to implicit conversion.

I think that in this case, the string would be always chosen, because it matches exactly. But the algorithm is probably more general, and causes an error when it thinks it needs to know what type exactly that other overload has.

Example of the problematic situation:

class A
{}

class B
{
    public static implicit operator B(A a)
    {
        return null;
    }
}

class C
{
    public static implicit operator C(A a)
    {
        return null;
    }
}

public static void M(B b)
{}

public static void M(C a)
{}

Here, types B and C are from different assemblies. Now, if you call M(new A()), which overload would be chosen could depend on what assemblies are referenced. Since such behavior is undesirable, the compiler gives up, to be on the safe side.

Like I said, your sample is not exactly like this, but it's likely the compiler follows the same rules.

Tether answered 16/2, 2012 at 1:48 Comment(1)
Agreed. Though, it seems that implicit conversion shouldn't matter if the passed parameters exactly match the types of a given overload. Perhaps there's a scenario where the algorithm being less general would not be safe; if so it'd be interesting to see an example of that.Nananne

© 2022 - 2024 — McMap. All rights reserved.