Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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]

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.

like image 263
Tyler Laing Avatar asked Feb 16 '12 01:02

Tyler Laing


1 Answers

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.

like image 129
svick Avatar answered Nov 04 '22 09:11

svick