project-system icon indicating copy to clipboard operation
project-system copied to clipboard

Allow modifying set of implicit global usings for .NET 6 projects

Open drewnoakes opened this issue 4 years ago • 13 comments

.NET 6 provides a new feature, "implicit global usings".

We should add tooling support to it in the new Project Property UI.

Relates to https://github.com/dotnet/sdk/issues/19521

At a high level this involves:

  • A new <ImplicitUsings> property, with values of enable, true and disable
  • New <Using Include="..." ... /> items

The property will be straightforward, but the new items will likely require some custom UI as they are not just a simple string list and allow metadata such as Alias and Static.

The MSBuild XSD was updated with these values in https://github.com/dotnet/msbuild/pull/6755

drewnoakes avatar Aug 16 '21 01:08 drewnoakes

true and enable are aliases. We should only define one in the UI (a checkbox would suffice for now) and we should alias these two values via an interceptor.

drewnoakes avatar Aug 17 '21 12:08 drewnoakes

As custom UI is potentially challenging here, an intermediate solution may be to support multi-line text, with values of the form:

System
System.Collections.Generic
Foo = MyNamespace.Bar
static Foo.Bar

Which would map to:

<ItemGroup>
  <Using Include="System" />
  <Using Include="System.Collections.Generic" />
  <Using Include="MyNamespace.Bar" Alias="Foo" />
  <Using Include="Foo.Bar" Static="true" />
</ItemGroup>

drewnoakes avatar Aug 17 '21 12:08 drewnoakes

Also investigate DisableImplicitNamespaceImports.

https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#disableimplicitnamespaceimports

drewnoakes avatar Aug 19 '21 13:08 drewnoakes

Also investigate DisableImplicitNamespaceImports.

It seems that this varies by project language, which we will have to respect in the UI:

  • DisableImplicitNamespaceImports is VB only
  • ImplicitUsings is C# only

See the first few bullet points on https://github.com/dotnet/sdk/issues/19521 for info.

drewnoakes avatar Aug 22 '21 23:08 drewnoakes

Thanks for tracking that down. I thought for a second we'd just left the extra property in by mistake but it looks like it existed before for VB and they didn't want to make the breaking change.

marcpopMSFT avatar Aug 23 '21 20:08 marcpopMSFT

#7512 adds a check box that controls whether the feature is enabled.

The ability to modify the set of includes is still pending, and this issue is now tracking that.

drewnoakes avatar Aug 30 '21 23:08 drewnoakes

I came across this thread because after using VS2022 for a week I wanted to find out why the global/implicit usings implementation is designed the way it is. I am disappointed with the current design because I feel like it excludes configurability and usability in favor of no other perceptible gain except, perhaps, brevity.

Specifically:

1.) There is no facility for the developer to maintain their own set of implicit usings. This needs to be a Visual Studio setting so the usings are created for each new project.

2.) Developer needs to be able to choose if they want to use a single file dedicated to global usings. If so, developer needs to be able to supply their own name for the file.

3.) VS needs to create the named global usings file when project is created, if applicable.

Items 2 and 3 above will give VS the ability to create a using statement in the correct file if the developer uses intellisense to create the using statement. The current design breaks the intellisense feature (using statement is added to current file only - not global usings file).

Items 2 and 3 eliminate the need to create a global usings file in the obj folder (not that there was a need to begin with).

Proposed functionality will create a new global usings file when a project is created and populate that file with SDK + developer defined usings statements (implicit). Global usings file will be readable and editable by the developer and will allow VS intellisense to continue to work correctly.

sam-wheat avatar Dec 01 '21 03:12 sam-wheat

@sam-wheat we definitely want to provide control over the set of implicit usings added to the project.

Despite the lack of UI for this currently, it's still possible to specify your own set of usings and share them across projects.

For example, in a Directory.Build.props file, you can add:

<ItemGroup>
  <Using Remove="System.Collections.Generic" />
  <Using Include="My.Collections.Namespace" />
</ItemGroup>

...and this will be picked up by all projects beneath the folder that contains that file.

You can also create a .cs file with eg: global using My.Collections.Namespace;, and link that source file into your projects.

drewnoakes avatar Dec 07 '21 11:12 drewnoakes

Thank you Drew. Couple questions about Directory.Build.props: Will VS create this file when a .sln is created and populate it with selected usings? Will VS use this file when populating a using from Intellisense? Given the availability of Directory.Build.props what is the purpose of the usings file created in the obj folder?

BTW I like the idea of a standardized name/location for global usings.

sam-wheat avatar Dec 10 '21 14:12 sam-wheat

Will VS create this file when a .sln is created and populate it with selected usings?

VS doesn't create this file. You'll need to do it manually.

Given the availability of Directory.Build.props what is the purpose of the usings file created in the obj folder?

The process is:

  • project declares usings in MSBuild files (.csproj, .props, etc)
  • during build the .cs file is generated in the obj folder
  • compiler uses the .cs file

Will VS use this file when populating a using from Intellisense?

Yes.

BTW I like the idea of a standardized name/location for global usings.

Directory.Build.props is the best place for standardising things across a solution, or perhaps across the src or test folder, for example. There's no UI support for this in VS currently, but it's not hard to set up manually. You can add the file as a solution item in Solution Explorer.

drewnoakes avatar Dec 10 '21 21:12 drewnoakes

I thought I would give it a try for kicks and giggles. Added Directory.Build.props in the same folder as my .sln:

<Project>
	<ItemGroup>
		<Using Include="Autofac"/>
		<Using Include="Autofac.Extensions.DependencyInjection"/>
		// etc...

On build I get multiple errors becuse not all of my projects are referencing assemblies mentioned in Directory.Build.props. The error occurs in the generated file:

// <auto-generated/>
global using global::Autofac;				// valid
global using global::Autofac.Extensions.DependencyInjection;			// error

I tried referencing a .cs file I created also in the same folder and as the .sln. Added the file to one of my projects as a link and opend it. Not surprisingly I get the same errors as the generated file:

global using Autofac;		// valid
global using Autofac.Extensions.DependencyInjection;		// error

https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022

https://github.com/dotnet/sdk/issues/19521

leaderanalytics avatar Dec 12 '21 02:12 leaderanalytics

@leaderanalytics the following might be useful for you. I'm not saying this is supported or recommended, but in my limited testing it seems to work. If you add the Using item in a Directory.Build.targets file, you can condition them based upon the presence of a particular PackageReference in each project that picks the file:

<Project InitialTargets="AddGlobalUsingItems">
  <Target Name="AddGlobalUsingItems">
    <ItemGroup>
      <Using Include="Autofac" Condition="'%(PackageReference.Identity)' == 'Autofac'" />
    </ItemGroup>
  </Target>
</Project>

Unfortunately this requires an MSBuild <Target>, as the form of the Condition expression is not supported in evaluation, only during build (and therefore only in targets).

drewnoakes avatar Dec 15 '21 01:12 drewnoakes

We may be able to take advantage of the MultiStringSelector editor for this.

adamint avatar Jun 29 '22 19:06 adamint