Search code examples
c#.netcompiler-errors

Why am I getting this definition reference error?


I am using TaskBar methods defined within the namespace Microsoft.WindowsAPICodePack.Taskbar. Specifically, I'll focus on SetProgressState for this question.

Here is the meta-definition I get when I ask for the definition of SetProgressState:

namespace Microsoft.WindowsAPICodePack.Taskbar
{
    public class TaskbarManager
    {
        public void SetProgressState(TaskbarProgressBarState state);
        public void SetProgressState(TaskbarProgressBarState state, IntPtr windowHandle);
        public void SetProgressState(TaskbarProgressBarState state, System.Windows.Window window);
    }
}

Obviously, I have omitted most of that class's definition just to highlight the one method's overloads.

To this point, I have been using the single-parameter overload and have had no issues. However, today I attempted to use the two-parameter overload that accepts an IntPtr as its second parameter.

When I did that, I started getting this error during build:

The type 'System.Windows.Window' is defined in an assembly that is not referenced. You must add a reference to assembly 'PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

So my question is why I did not get an error for using the single-parameter overload, but I do get an error for referencing one of the others (and for the wrong one)?

Edit (for addition sub-question):

I also tried the following, which made no difference:

SetProgressState(myState, (IntPtr) myWindowHandle);

I thought that by casting explicitly, I would avoid the compiler confusion in realizing the appropriate overload, but that was not the case.


Solution

  • According to the MSDN page on Overload Resolution, the compiler will start by selecting the potential candidates

    Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way

    then, the best target is selected:

    If the set contains only one function member, then that function member is the best function member.

    My understanding here is that the compiler doesn't even consider the 2 arguments methods when you call it with 1 argument. However, when you use the 2 arguments version, it needs information about the argument types. In this case, it needs to know what System.Windows.Window is to be able to determine which overload you want to call.

    Example

    Imagine you have 2 classes in separate Class Libraries

    class Foo
    {
    
    }
    
    class Bar : Foo
    {
    
    }
    

    and 4 methods in an other library

    static void Do()
    {
    
    }
    
    static void Do(Foo foo)
    {
    
    }
    
    static void Do(Bar bar)
    {
    
    }
    
    static Foo Get()
    {
        return new Bar();
    }
    

    You reference the Methods Library and the Library Containing Foo, but not the library containing Bar.

    Then, in your application, you obtain an object of type Foo from the Methods Library (it could be a Bar too, but you don't know). How is the compiler supposed to resolve an eventual call to Do() with arguments?

    It can't unless it has the type information for Bar as well.


    As for your subquestion, it's a result of the above plus the fact that a cast doesn't necessarily force an overload to be chosen. Let's imagine that System.Windows.Window derives from IntPtr for a moment. Casting the argument to IntPtr doesn't help the compiler resolve the overload at all (see above example).

    Since the type information is not present, the compiler emits an error because it can't know for sure. Honestly, for compilers, that's a feature.