简体   繁体   中英

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).

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 ).

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.

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 ):

 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(); }  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(); } 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(); }  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(); } 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.

well, yes! In order to compile, it needs to be able to resolve everything in the public/protected 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. 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. This is standard behavior.

@Marc gives you the why. 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. Then you can include both in web projects and only the non-web extensions in other projects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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