在单独的程序集中使用受限泛型扩展方法会导致引用错误。

5
我创建了一个单独的程序集来包含通用的扩展方法,这些扩展方法使用了System.Web.dll(和其他类)中的类。
当我创建一个新的项目(控制台应用程序),引用包含扩展方法的Utilities.dll程序集时,如果该项目没有使用扩展了System.Web.dll程序集中的任何类(例如System.Web.UI.Control),则不需要为该新项目添加对System.Web.dll的引用。
当我的某个扩展方法是泛型方法时,一切都按预期工作。但是,一旦我向泛型方法添加约束,将其限制为System.Web.dll程序集中的一个类,编译器就会抱怨我的新项目(控制台应用程序)需要引用System.Web.dll,即使该新项目仍然没有使用该程序集中的任何内容。
换句话说,只要我的泛型方法没有约束,一切都可以编译,但是一旦我添加约束,编译器就会抱怨。
下面是我的扩展方法程序集的示例(编译为库Utilities.dll):
public static class StringExtensions
{
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
}

public static class ControlExtensions
{
    // If I remove the where clause it compiles
    public static T FildChild<T>(this Control parent, string id)
        where T : Control
    {
        throw new NotImplementedException();
    }
}

以下是一个新的控制台应用程序,如果我不添加对 System.Web.dll 的引用,它将无法编译:

    static void Main(string[] args)
    {
        bool isEmpty = "Hello World!".IsNullOrEmpty();

        Console.ReadLine();
    }
更新: 正如Marc在下面指出的那样,将有问题的方法放在单独的命名空间中可以解决这个问题。
但问题仍然存在,为什么约束会成为问题,而类型Control已经被用作方法的参数。为什么命名空间是解决方案,当我已经在顶部使用了using指令。
2个回答

5

是的!为了编译,它需要能够解析公共/受保护 API 中的所有内容。否则它无法强制执行约束条件。我想它需要识别类型以查看扩展方法是否符合方法的候选条件。

你可以尝试将扩展方法放在一个子命名空间中,其中包含“Web” - 至少它就不会泄漏到常规代码中。我已经检查过了,这样就解决了这个问题。将扩展方法的命名空间分离开来以允许调用者控制它们何时处于范围内是一种好的做法。

为了执行,它还需要能够解析在 API 中未公开但在内部使用的任何内容。这是标准行为。


我不确定我完全理解。1)我的项目根本没有使用那种类型。2)扩展方法已经在方法的第一个参数中使用了该类型,为什么约束会触发这种疯狂? - Yona
我认为这并没有回答问题。即使将Control作为参数类型引用,他的代码也可以编译通过,但如果他将其添加为同一方法的约束条件,则无法编译通过。他甚至没有引用Control扩展类。 - Mike Scott
出乎意料的是,将有问题的方法放在一个单独的命名空间中(使用任何名称,只要它不与其他扩展名相同)可以解决这个问题。充其量很奇怪。 - Yona
但仍然没有回答为什么约束在这里会有所不同(类型已经在之前使用过)。 - Yona
猜测一下,分辨率意味着需要检查约束条件... 我得仔细看看它是否代表编译器错误或者只是预期的行为。无论哪种情况,名称空间技巧都可以避免这个问题。 - Marc Gravell

1

@Marc 给出了为什么。我建议您将任何涉及 Web 类的内容拆分成另一个程序集,例如 Com.Company.Extensions.Web,以及 Com.Company.Extensions。然后,您可以在 Web 项目中同时包含这两个程序集,而在其他项目中只包含非 Web 扩展。


这正是我所做的。我有一个<company>.WebUtilities.dll程序集。 - Yona
顺便说一句,我不确定我理解马克的回答,请检查我的评论。 - Yona

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接