简体   繁体   English

在单独的程序集中使用受约束的通用扩展方法会产生参考错误

[英]Using constrained generic extension methods in a separate assembly gives a reference error

I created a separate assembly to contain common extension methods, the extension methods uses classes from System.Web.dll (and others). 我创建了一个单独的程序集以包含常见的扩展方法,该扩展方法使用System.Web.dll (和其他)中的类。

When I then create a new project (Console Application) that references the Utilities.dll assembly that contains the extension methods, I do not need to add a reference to System.Web.dll to the new project if it does not use the extension methods that extends any class in the System.Web.dll assembly (for example System.Web.UI.Control ). 然后,当我创建一个引用包含扩展方法的Utilities.dll集的新项目(控制台应用程序)时,如果它不使用扩展方法,则不需要在新项目中添加对System.Web.dll的引用。扩展了System.Web.dll程序集中的任何类(例如System.Web.UI.Control )。

When one of the extension methods will be a generic method everything continues to work as expected. 当一种扩展方法将是通用方法时,一切将继续按预期工作。 But as soon as I add a constraint to the generic method that constraines it to a class in the System.Web.dll assembly the compiler will complain that my new project (Console Application) needs a reference to System.Web.dll even though the new project is still not using anything in that assembly. 但是,一旦我在将通用方法约束到System.Web.dll程序集中的类的方法中添加了约束,编译器就会抱怨我的新项目(控制台应用程序)需要引用System.Web.dll即使新项目仍未在该程序集中使用任何内容。

In other words as long as I dont have a constraint on my generic methods everything compiles but as soon as I add a constraint the compiler complains. 换句话说,只要我对通用方法没有约束,一切都会编译,但是一旦添加约束,编译器就会抱怨。

An example of my extension methods assemble (compiled as a library Utilities.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(); } } And here is a new console application that won't compile (unless I also add a reference to System.Web.dll ):  static void Main(string[] args) { bool isEmpty = "Hello World!".IsNullOrEmpty(); Console.ReadLine(); } Update: As Marc pointed out (below) puting the offending method in a separate namespace fixes the problem. 

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(); } } And here is a new console application that won't compile (unless I also add a reference to System.Web.dll ): static void Main(string[] args) { bool isEmpty = "Hello World!".IsNullOrEmpty(); Console.ReadLine(); } Update: As Marc pointed out (below) puting the offending method in a separate namespace fixes the problem.

 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(); } } And here is a new console application that won't compile (unless I also add a reference to System.Web.dll ):  static void Main(string[] args) { bool isEmpty = "Hello World!".IsNullOrEmpty(); Console.ReadLine(); } Update: As Marc pointed out (below) puting the offending method in a separate namespace fixes the problem. 


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(); } } And here is a new console application that won't compile (unless I also add a reference to System.Web.dll ): static void Main(string[] args) { bool isEmpty = "Hello World!".IsNullOrEmpty(); Console.ReadLine(); } Update: As Marc pointed out (below) puting the offending method in a separate namespace fixes the problem.

But the question still remains why is the constraint a problem while the type Control was already used as a parameter to the method. and why is the namespace the solution when I already use the using But the question still remains why is the constraint a problem while the type Control was already used as a parameter to the method. and why is the namespace the solution when I already use the using directive at the top. But the question still remains why is the constraint a problem while the type Control was already used as a parameter to the method. and why is the namespace the solution when I already use the using在顶部But the question still remains why is the constraint a problem while the type Control was already used as a parameter to the method. and why is the namespace the solution when I already use the using指令But the question still remains why is the constraint a problem while the type Control was already used as a parameter to the method. and why is the namespace the solution when I already use the using

well, yes! 嗯,是! In order to compile, it needs to be able to resolve everything in the public/protected API. 为了进行编译,它需要能够解析公共/受保护的API中的所有内容。 Otherwise it can't enforce the constraint. 否则它将无法强制执行约束。 I imagine it needs to recognise the types to see if the extension method is a candidate for a method. 我想它需要识别类型以查看扩展方法是否是方法的候选方法。

You could try placing the extension methods in a child namespace that has "Web" in it - at least then it won't spill into regular code. 您可以尝试将扩展方法放置在其中带有“ Web”的子命名空间中-至少这样,它将不会溢出到常规代码中。 I've checked , and this fixes the issue. 我已经检查了 ,这可以解决问题。 It is good practice to separate the namespaces of extension methods to allow the caller to control when they should be in scope. 优良作法是将扩展方法的命名空间分开,以允许调用方控制它们何时应在范围内。

In order to execute, it would also need to be able to resolve anything used internally but not exposed in the API. 为了执行,还需要能够在内部而不是使用API暴露解决任何问题。 This is standard behavior. 这是标准行为。

@Marc gives you the why. @Marc为您提供了原因。 I would suggest that as a good practice you break out anything that refers to web classes into yet another assembly, say Com.Company.Extensions.Web in addition to Com.Company.Extensions. 我建议,作为一种好的做法,除了Com.Company.Extensions外,还应将引用Web类的所有内容分解为另一个程序集,例如Com.Company.Extensions.Web。 Then you can include both in web projects and only the non-web extensions in other projects. 然后,您既可以将其包含在Web项目中,也可以仅将非Web扩展名包含在其他项目中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM