【问题标题】:Why am I getting this definition reference error?为什么我会收到此定义参考错误?
【发布时间】:2013-06-26 14:01:57
【问题描述】:

我正在使用命名空间Microsoft.WindowsAPICodePack.Taskbar 中定义的TaskBar 方法。具体来说,这个问题我会关注SetProgressState

这是我在询问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);
    }
}

显然,我省略了该类的大部分定义,只是为了突出一个方法的重载。

到目前为止,我一直在使用单参数重载并且没有遇到任何问题。但是,今天我尝试使用接受IntPtr 作为其第二个参数的双参数重载。

当我这样做时,我在构建期间开始收到此错误:

类型“System.Windows.Window”是在一个不是 参考。您必须添加对程序集的引用 'PresentationFramework,版本=3.0.0.0,文化=中性, PublicKeyToken=31bf3856ad364e35'

所以我的问题是为什么我在使用单参数重载时没有收到错误,但我确实在引用其他参数之一时遇到了错误(以及 错误的)?

编辑(添加子问题):

我也尝试了以下方法,没有任何区别:

SetProgressState(myState, (IntPtr) myWindowHandle);

我认为通过显式转换,可以避免编译器在实现适当的重载时混淆,但事实并非如此。

【问题讨论】:

  • 只是等待 Eric Lippert 过来,但我猜:您可以链接使用项目引用的类型的重载,但只要编译器/链接器必须检测到最佳匹配(因为有多个双参数重载,它必须检查所有重载),它必须知道所有可能的拟合重载正在使用的所有类型。也许从 C# 规范中阅读 7.4.2 Overload Resolution
  • @CodeCaster 我也怀疑过,但后来我想知道为什么这没有什么不同:SetProgressState(myState, (IntPtr) myWindowHandle);。这不应该让我想要的编译器清楚吗?
  • 另外,您可能需要仔细检查您的项目中是否引用了 PresentationFramework 并且您是 #using System.Windows。最坏的情况,检查对象浏览器中的Windows.Window
  • @RyanWH 对System.Windows 的引用也没有区别,因为它专门要求System.Windows.Window。为了清楚起见(因为问题不是),如果可能的话,我会尽量避免额外的参考。
  • @DonBoitnott 因为编译器不只是为了快乐的情况而存在。 :-) 它不应该只返回第一个最佳匹配,而是将它们全部列出以检测是否存在模棱两可的匹配。

标签: c# .net compiler-construction compiler-errors


【解决方案1】:

根据MSDN page on Overload Resolution,编译器将首先选择潜在的候选者

每个上下文都以自己独特的方式定义候选函数成员集和参数列表

然后,选择最佳目标:

如果该集合仅包含一个函数成员,则该函数成员是最佳函数成员。

我的理解是,当您使用 1 个参数调用它时,编译器甚至不会考虑 2 个参数方法。但是,当您使用 2 参数版本时,它需要有关参数类型的信息。在这种情况下,它需要知道System.Windows.Window 是什么才能确定您要调用哪个重载。

示例

假设您在不同的类库中有 2 个类

class Foo
{

}

class Bar : Foo
{

}

以及其他库中的 4 个方法

static void Do()
{

}

static void Do(Foo foo)
{

}

static void Do(Bar bar)
{

}

static Foo Get()
{
    return new Bar();
}

您引用了方法库和包含Foo 的库,但没有引用包含Bar 的库。

然后,在您的应用程序中,您从方法库中获得一个Foo 类型的对象(它也可能是Bar,但您不知道)。编译器应该如何使用参数解决对Do() 的最终调用?

它不能,除非它也有 Bar 的类型信息。


至于您的子问题,这是上述情况的结果,加上强制转换不一定强制选择重载这一事实。让我们暂时假设System.Windows.Window 派生自IntPtr。将参数转换为 IntPtr 根本无法帮助编译器解决重载问题(参见上面的示例)。

由于类型信息不存在,编译器会发出错误因为它无法确定。老实说,对于编译器来说,这是一个特性。

【讨论】:

  • 按照 CodeCaster 的建议,玩了一会儿并阅读了有关重载解决方案的信息后,我相信您已经明白了。谢谢。
【解决方案2】:

为了清楚起见,我将在这里扩展我的 cmets。您的项目找不到 System.Windows.Window。当我说你需要输入时,我在评论中说错了:

using System.Windows;

到文件。

相反,项目需要引用 System.Windows。您想要的参考在错误消息中提供给您:PresentationFramework。您还需要包含 PresentationCore(会弹出一个类似的错误,告诉您添加对 PresentationCore 的引用)。

“System.Windows.Window”类型是在未引用的程序集中定义的。您必须添加对程序集 'PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

的引用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-22
    • 2016-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2012-02-19
    相关资源
    最近更新 更多