【问题标题】:Two extension methods with same name两个同名的扩展方法
【发布时间】:2015-02-27 18:08:00
【问题描述】:

我有以下两个扩展方法(方法的主体对我的问题并不是特别重要,但无论如何包括代码)

public static class DictionaryExtensions
{
    public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> source, TKey key, TValue defaultValue)
    {
        return (source.ContainsKey(key) ? source[key] : defaultValue);
    }
}

public static class WebExtensions
{
    public static T GetValue<T>(this HttpContext context, string name, T defaultValue)
    {
        object value = context.Request.Form[name] ?? context.Request.QueryString[name];
        if (value == null) return defaultValue;
        return (T)value;
    }
}

这两个方法共享相同的名称,但它们扩展了两种截然不同的类型。我希望以下代码很简单,并且编译器能够选择适当的扩展方法:

var myDict = new Dictionary<int, string>()
{
    { 1, "foo" },
    { 2, "bar" }
};
var result = myDict.GetValue(5, "baz");

但是,由于某些未知原因,Visual Studio 拒绝编译我的代码,并出现以下编译时错误:“类型 'System.Web.HttpContext' 在未引用的程序集中定义。您必须添加引用组装'System.Web'”。这个错误告诉我编译器选择了 WebExtensions 类中的 GetValue 扩展方法,而不是 DictionaryExtension 类中的方法。

我能够解决以下问题:

var result = DictionaryExtensions.GetValue(myDict, 5, "baz");

但我试图理解为什么编译器首先会感到困惑。有人知道为什么吗?

【问题讨论】:

  • 我无法重现您的问题。 dotnetfiddle.net/gNPuvD
  • DictionaryExtensionsWebExtensions 是否都定义在同一个程序集中?还是不同的组件?听起来您的项目只需要引用 System.Web.dll 即可编译。
  • @danludwig 他们在同一个程序集中。我有一个程序集,其中对所有扩展方法进行了分组。但是,它与调用它们的位置不同。
  • 您的错误表明您没有引用它需要定义HttpContext 的程序集,而不是它无法推断出您想要的方法。
  • @Selman22 因为System.Web 命名空间已经包含在小提琴中。

标签: c# extension-methods


【解决方案1】:

只需按照编译器的说明进行操作,然后添加对 System.Web.dll 的引用即可。然后它应该编译。

存在这些扩展方法类的外部程序集依赖于 System.Web.dll。编译器应该能够找出重载,但为了做到这一点,它需要引用 System.Web.dll 中存在HttpContext 的程序集。

另一方面,如果您不希望使用扩展方法程序集的项目依赖 System.Web.dll,那么您需要在单独的程序集中定义这 2 个扩展方法类。

@Steve Danner has a good solution too:将两个扩展方法类放到同一个程序集中的不同命名空间中,对于包含WebExtensions类的命名空间省略using语句。

我偶尔会遇到 System.Runtime.Serialization、System.ServiceModel.Activation 等问题。当您有一个被两次删除的依赖项时,可能会发生这种情况。换句话说,您的根项目依赖于一个程序集,该程序集依赖于另一个第三程序集的类型。

【讨论】:

  • 好的,我会试试的。虽然在不需要的时候添加对 System.Web 的引用很奇怪。
  • 如果您不希望依赖于 System.Web.dll,请在包含 DictionaryExtensions 类的单独程序集中定义使用 HttpContext 的扩展方法。跨度>
  • ...或者,正如我在问题中提到的,只需使用 var result = DictionaryExtension.GetValue() 语法。
  • 是的,因为编译器不必解决重载问题(两个具有相同名称的扩展方法)。当您将其编写为静态方法时,编译器不必解析扩展方法重载。
  • 好的,我按照您的建议添加了对 System.Web 的引用,确实错误消失了,我的代码编译了。我将坚持使用“DictionaryExtension.GetValue”语法,因为我真的不想要额外的参考,但你帮助我理解了编译器为什么会感到困惑。谢谢。
【解决方案2】:

另一种选择是将您的 2 个扩展类拆分为单独的命名空间,并且不要添加一个 using 语句,其中 WebExtensions 类驻留在您的消费代码中。这样编译器就不会尝试将GetValue 解析为WebExtensions

【讨论】:

  • 这比两个程序集要好得多。所有这一切的重点是,如果您不引用程序集,编译器就无法运行重载解析。这与使用标准方法语法相同的方式取出重载决议。
猜你喜欢
  • 2021-03-14
  • 2011-10-25
  • 2011-01-01
  • 1970-01-01
  • 2016-12-21
  • 1970-01-01
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多