【问题标题】:C# extension method overloading causes "missing assembly reference" errorC# 扩展方法重载导致“缺少程序集引用”错误
【发布时间】:2023-03-07 08:05:01
【问题描述】:

有对应的VS开发票https://connect.microsoft.com/VisualStudio/feedback/details/817276/error-cs0012-the-type-is-defined-in-an-assembly-that-is-not-referenced-issued-for-an-extension-method-that-is-not-used

我有两种扩展方法:

public static class ExtensionMethods
{
    public static string GetClientIpAddress(this HttpRequestBase request)
    {
        // ...
    }

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
        // ...
    }
}

HttpRequestMessage 类位于 System.Net.Http 程序集中,HttpRequestBase 位于 System.Web 中(即在不同的程序集中)。 ExtensionMethods 类位于 ProjectA 中。

这个项目编译良好,没有问题。

然后我使用另一个项目中的第一种方法GetClientIpAddress(this HttpRequestBase request)(比如说ProjectB),如下所示:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    base.OnActionExecuting(filterContext);
    var sessionContext = DependencyResolver.Current.GetService<ISessionContext>();

    // Call to GetClientIpAddress
    sessionContext.ClientIpAddress =
        filterContext.HttpContext.Request.GetClientIpAddress();
}

ProjectB 已经引用了System.Web,但是当我尝试编译它时,它会导致编译器错误:

类型“System.Net.Http.HttpRequestMessage”在未引用的程序集中定义。您必须添加对程序集“System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”的引用。

我不明白为什么要添加对System.Net.Http的引用。

编译器似乎尝试使用第二种方法GetClientIpAddress(this HttpRequestMessage request),这会导致缺少对程序集的引用。这是一个错误吗?

当我重命名第一个方法(即摆脱重载)时,一切都编译得很好。

【问题讨论】:

  • 扩展方法可能使用了Web项目中未引用的某些程序集
  • 在编译器可以看到所有类型的定义之前,并不知道您打算调用第一个方法。它需要查看所有类型以执行重载解析
  • ProjectB 已经同时引用了 System.Net.Http 和 System.Web,所以不是这种情况。请参阅下面的编辑。
  • 您忘记记录您的 .NET 框架目标。但是您选择 4.0 并且不恰当地将客户端配置文件用于您的 EXE 项目的可能性很高。将其更改为完整版,该版本还包括 System.Web
  • “编译器似乎尝试使用第二种方法......” - 不,正如我在第一条评论中试图指出的那样,它甚至没有走那么远。它在您的代码中找到了一个符号GetClientIpAddress。现在必须确定您打算调用的方法。它找到了两个候选人。它现在需要确定它应该调用两个候选人中的哪一个。为了做到这一点,它需要了解 both 方法的所有参数类型,以便找出唯一的最佳方法,或者调用是否不明确等。如果它不理解第二种方法的参数类型。

标签: c# extension-methods c#-5.0


【解决方案1】:

来自 C# 5.0 规范,第 7.5.3 节:

给定一组适用的候选函数成员,找到该集合中的最佳函数成员。如果该集合仅包含一个函数成员,则该函数成员是最佳函数成员。否则,最好的函数成员是在给定参数列表方面优于所有其他函数成员的一个函数成员,前提是使用第 7.5.3.2 节中的规则将每个函数成员与所有其他函数成员进行比较。

第 7.5.3.2 节:

给定一个带有一组参数表达式的参数列表 A { E1, E2, ..., EN } 和两个适用的函数成员 MP 和 MQ,参数类型为 { P1, P2, ... , PN } 和 { Q1, Q2, ..., QN }, MP 被定义为比 MQ 更好的函数成员 if

• 对于每个参数,从 EX 到 QX 的隐式转换并不比从 EX 到 P 的隐式转换好X

• 对于至少一个参数,从 EX 到 PX 的转换优于从 EX 到 QX.

没有规则“如果参数类型与参数类型完全匹配,则选择那个” - 因此编译器需要有关所有参数类型的完整类型信息才能评估上述规则。

为了解决问题而不必添加对System.Net.Http 的引用?您已经找到了答案 - 使用不同的方法名称。由于之前引用的 7.5.3 部分,这让您成功:

如果集合只包含一个函数成员,那么那个函数成员是最好的函数成员

【讨论】:

  • 是的,我同意“...所以编译器需要关于所有参数类型的完整类型信息才能评估上述规则。”我认为它已经包含了所有需要的信息,因为 ProjectA 已经引用了 System.Net.Http 并且编译器可以使用它来解析参数类型。对吗?
  • @neleus - 不,引用不可传递。在编译项目 B 时,只需要考虑项目 B 的代码及其引用。
  • 现在我明白了,感谢您的详细描述。在这种情况下,我会建议微软改进他们的编译器,这将是一个非常好的功能。
【解决方案2】:

我也做了一个没有扩展方法的简单测试,得到了同样的效果。 正如 Damien_The_Unbeliever 所说,这个问题仅与方法重载有关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    相关资源
    最近更新 更多