microsoft / dotnet

This repo is the official home of .NET on GitHub. It's a great starting point to find many .NET OSS projects from Microsoft and the community, including many that are part of the .NET Foundation.
https://devblogs.microsoft.com/dotnet/
MIT License
14.33k stars 2.21k forks source link

4.7.2 introduces CS0121 #730

Open RichardD2 opened 6 years ago

RichardD2 commented 6 years ago

I have a number of WebForms sites which are not pre-compiled, targeting 4.5, which have been working for years.

The site references a class library which includes a custom ToHashSet extension method. This extension method is used in various places.

After installing the Win10 April update - and thereby, .NET 4.7.2 - the site fails to compile. Each usage of the custom extension method from a class in the App_Code folder is flagged as ambiguous between my custom extension method and the new Enumerable.ToHashSet extension method.

Usages of my custom extension method in code-behind files are not marked as ambiguous.

I accept that the "web site" model is not recommended. However, rewriting several large sites to use the "web application" model is not an option.

The compiler is clearly capable of ignoring new APIs; otherwise, the code-behind code would not compile. So why is it not doing so for code in the App_Code folder?

{path}\WWW\App_Code\Catalogues\CatalogueOrderFactory.cs(31):

error CS0121: The call is ambiguous between the following methods or properties: 'NBS.Core.Collections.Generic.SetExtensions.ToHashSet(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEqualityComparer)' and 'System.Linq.Enumerable.ToHashSet(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEqualityComparer)'

at System.Web.Compilation.AssemblyBuilder.Compile() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at System.Web.Compilation.CodeDirectoryCompiler.GetCodeDirectoryAssembly(VirtualPath virtualDir, CodeDirectoryType dirType, String assemblyName, StringSet excludedSubdirectories, Boolean isDirectoryAllowed) at System.Web.Compilation.BuildManager.CompileCodeDirectory(VirtualPath virtualDir, CodeDirectoryType dirType, String assemblyName, StringSet excludedSubdirectories) at System.Web.Compilation.BuildManager.CompileCodeDirectories() at System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() at System.Web.Compilation.BuildManager.CallAppInitializeMethod() at System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException)

RichardD2 commented 6 years ago

I've recreated the problem in a small project, which is available here: Test472

If you compile the site, it succeeds. As soon as you run it, you'll get:

CS0121: The call is ambiguous between the following methods or properties: 'Test472.Core.SetExtensions.ToHashSet(System.Collections.Generic.IEnumerable)' and 'System.Linq.Enumerable.ToHashSet(System.Collections.Generic.IEnumerable)'

In this case, both the call from App_Code and the call from the code-behind seem to trigger the problem.

Jinhuafei commented 6 years ago

Asp.net runtime compilation references the .net framework installed on your machine. Unfortunately, new API System.Linq.Enumerable.ToHashSet is added into 4.7.2 which causes the issue.

So there are several options here:

  1. if you have the control of the extension lib, you can rename the extension method.
  2. call the extension method explicitly in your app
  3. precompile your web site on the machine with lower version of .net framework installed
harrisse commented 5 years ago

This is affecting us as well, is this method also available for .NET Standard? I can't seem to find it anywhere. This leaves us in a state where some of our code has to get ToHashSet from our custom extension methods and some has to get it from .NET Framework.

BcMartinSulcNess commented 5 years ago

4.7.2 Problem: HashSet<int> hashSet = yourCollection.ToHashSet(); Solution: HashSet<int> hashSet = new HashSet<int>(yourCollection);

Update @RichardD2 :-D generic parameters was there but if you set text as BOLD, so it disappears in the preview. Thanks for the note. I changed BOLD to CODE and we can see parameters :-)

RichardD2 commented 5 years ago

@BcMartinSulcNess You're missing the type parameters, so that won't compile. It would actually be:

HashSet<SomeType> hashSet = yourCollection.ToHashSet();

and:

HashSet<SomeType> hashSet = new HashSet<SomeType>(yourCollection);

It still requires changes to existing code which was working prior to the installation of 4.7.2 though.

vrohit13 commented 5 years ago

We also faced this issue, although dealing with Dot Net v.4.60 (started few months back). The code suggested by @BcMartinSulcNess worked for us.

For some reason HashSet<int> hashSet = yourCollection.ToHashSet(); does not work with Version: 4.6.00081, but works with Version: 4.6.01055.

fowl2 commented 3 years ago

I think the only way to fix this would be introducing a .NET Standard 2.0.1 that targeted .NET Framework 4.7.2.

Given the prevailing attitudes to "legacy", even changes like this to make upgrading easier, it seems unlikely :/