Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change default namespace associated to a folder when creating new class #5372

Open
vsfeedback opened this issue Aug 26, 2019 · 41 comments
Open
Labels
Triage-Approved Reviewed and prioritized
Milestone

Comments

@vsfeedback
Copy link

vsfeedback commented Aug 26, 2019

This issue has a corresponding ticket on Developer Community. Please vote and comment there to make sure your voice is heard.


It would be nice if there is a feature to set a default namespace for each folder when creating a new class. For example, if we have the following file structure:

MyProject
     MyFolder
          MyClass1

Then if we create MyClass2 under MyFolder, the created class will be under the MyProject namespace instead of MyProject.MyFolder.

Additional references: https://stackoverflow.com/questions/1317901/change-default-namespace-when-creating-class-in-folder-visual-studio

@drewnoakes
Copy link
Member

To paraphrase, the request is to be able to mark a folder with metadata to stop it from participating in namespace construction.

@davkean
Copy link
Member

davkean commented Aug 27, 2019

Yep interesting and reasonable request. We don't have the ability to associate metadata with a folder in CPS - other than empty folders, they don't have a item representation, so we'd need to introduce that.

@davkean davkean added this to the Backlog milestone Aug 27, 2019
@JimF42
Copy link

JimF42 commented Oct 4, 2019

@davkean You might want to look at this feedback post I created. Admittedly, this was before I realized that ReSharper was doing part of this...
https://developercommunity.visualstudio.com/content/problem/621033/adding-a-class-does-not-honor-namespace-provider-s.html

So somehow ReSharper is keeping meta data on the folder to determine if the folder name should be part of the namespace. If I add a new class via ReSharper (which I never do) it's honored. If I use VS to add a class, it's not honored (not surprisingly in hindsight).

Here is a small screenshot of a folder being selected and ReSharper's added property "Namespace Provider"

Folder Properties

Now, I am not expecting you to code to ReSharper's standard, but when you start working on this you may let them know so they can take it into account in their code. I would hate to see double folder properties and have to set them both not knowing which one is which.

@drewnoakes
Copy link
Member

ReSharper stores this data in their own resource file, outside of the project file. We would want to store it in the project file directly.

For example:

<ItemGroup>
  <Folder Include="Models\" IsNamespaceProvider="False" />
</ItemGroup>

Currently this Folder item is removed as soon as a class is added to that folder. We'd need to ensure Folder items with custom metadata are not removed in such cases.

@mrpmorris
Copy link

This is useful when we want to add all of our class extensions in an Extensions folder but want them all to be in the main namespace.

I think the best option would be to allow us to bring up the Properties window and edit a DefaultNameSpace property on the folder.

@davkean davkean added the Triage-Approved Reviewed and prioritized label Jan 17, 2020
@davkean
Copy link
Member

davkean commented Jan 17, 2020

@jinujoseph Are you tracking anything similar on your side?

@ocallesp ocallesp self-assigned this May 5, 2020
@Codentale
Copy link

This is useful when we want to add all of our class extensions in an Extensions folder but want them all to be in the main namespace.

Agree, this is quite common case when some folder need to be in parent namespace.
My thought:

  1. Create Virtual Folder in project (like solution virtual folder) with unique icon.
  2. Or ignore folder with special prefix like maybe @Extensions or _Extensions.
    both way are very clear to indicate all items in the folder are using parent namespace, which I think is better then ReSharper way.

@thomaslevesque
Copy link
Member

Any news on this? Is it being considered for a future update?

@CodeAngry
Copy link

CodeAngry commented Oct 15, 2020

This would be really useful!

Adding metadata to any C# Project folder to override default folder-structure based namespace with:

  • default namespace: (empty)
    would follow default functionality
  • absolute namespace: /Parent/Child
    allows full namespace override
  • relative namespace: Child or ./Child or ../../Child
    that would resolve based on parent Namespace (which obviously can be overridden itself).
  • no namespace: -
    this would use parent namespace without child participating in the name construction

And any file added to that folder will have the namespace based on the override when file is created. And this should only apply to new files. If you change the folder's virtual namespace, there should be no sync for existing files with the old namespace. That's the developer's job to rename.

This would really help because often, you find yourself wanting to structure (1 or multiple folders deep) files but need them all in the same namespace. It's quite a headache.

@PieterjanDeClippel
Copy link

In our case we have a project where we structure functionality under a seperate folder. Like everything for Customer is being filed under the Customer folder. But since there's also a DTO called Customer in another project we use the CustomerModule namespace for the classes in the Customer folder.

Now each time you add a new class it's being added in the Customer namespace. It would be handy if you could have a folderconfig or maybe projectconfig file (one in the entire project) where you could specify the options for class files for a specific folder/project

@drewnoakes
Copy link
Member

In addition to specifying that a folder does not participate in namespace construction, I can see it being useful to also specify the full namespace for a given folder, such that it ignores any project-level namespace and ancestor folder names.

@MhAllan
Copy link

MhAllan commented Nov 17, 2020

This is not flexible

<ItemGroup>
  <Folder Include="Models\" IsNamespaceProvider="False" />
</ItemGroup>

Should be

<ItemGroup>
  <Folder Include="Models\" Namespace="whatever I want or empty" />
</ItemGroup>

@drewnoakes
Copy link
Member

@MhAllan both have merits. Specifying the full namespace on folders is harder to maintain when moving folders or renaming ancestors.

@MhAllan
Copy link

MhAllan commented Nov 22, 2020

It should be, If I set a Namespace, that won't change by changing the hierarchy or renaming ancestors.

@mrpmorris
Copy link

mrpmorris commented Nov 22, 2020

@drewnoakes that's the whole point of the request, to break the link between namespace and folder location.

@drewnoakes
Copy link
Member

drewnoakes commented Nov 22, 2020

@drewnoakes that's the whole point of the request, to break the link between namespace and folder location.

Indeed. But there are multiple potential implementations, each with strengths and weaknesses.

Edit: I can see why my comment could be confusing out of context. I was referring to the idea of specifying the full path on each folder, rather than just opting a particular folder out of namespace construction.

@Ali-YousefiTelori
Copy link

I like these Examples:

1.Dynamic with folder name:

<ItemGroup>
  <Folder Include="Models\" Namespace="Example.Sale.Core.[FolderName]" />
</ItemGroup>

2.Static namespace:

<ItemGroup>
  <Folder Include="Models\" Namespace="Example.Sale.Core.Models" />
</ItemGroup>

3.Default from project namespace:

<ItemGroup>
  <Folder Include="Models\"/>
</ItemGroup>

@mrpmorris
Copy link

I think * would be better than [FolderName]

@wouterroos
Copy link

Hi,

Any idea on when this will be implemented?

@danielchalmers
Copy link

what do you think about basing the new namespace off whatever the majority of existing files have in that folder? that would avoid the need to store metadata with the folder and is completely automatic.

@RyanThomas73
Copy link

RyanThomas73 commented Sep 17, 2021

IMO, the flexibility of the Namespace="..." option is more advantageous than the simplicity of the IsNamespaceProvider="false" option.

Handling folder moves, changes, etc would be fairly easy to maintain for such special cases if variables or template placeholders can be provided to refer to the folder name/relative folder path.

<ItemGroup>
    <!-- These use the root/default namespace despite being in folders -->
    <Folder Include="Common\" Namespace="$(DefaultNamespace)" />
    <Folder Include="Root\" Namespace="$(DefaultNamespace)" />
    
    <!-- These use a special namespace prefix + the folder names -->
    <Folder Include="Special\" Namespace="Some.Special.Namespace.$(FolderNameVarOrTemplateId)" />
</ItemGroup>

Another nice to have would be a way to define/overwrite the namespace pattern for new files at a higher level, like a project wide setting. Something like this maybe?

<PropertyGroup>
    <!-- Default behavior of my.namespace.folder.names -->
    <NamespaceGeneration Pattern="$(DefaultNamespace).$(RelativeFolderPath)" NamespacePathSeparator="." />
 </PropertyGroup>
 
 <PropertyGroup>
     <!-- In this project always use the root/default namespace regardless of folder path
     <NamspaceGeneration Pattern="$(DefaultNamespace)" />
 </PropertyGroup>
 
 <PropertyGroup>
    <!-- Default behavior except in lieu of my.namespace.some._folder it would be my.namespace.some.folder -->
     <NamespaceGeneration>
         <Pattern>$(DefaultNamespace).$(RelativeFolderPath.Replace("_", "")</Pattern>
     </NamespaceGeneration>
 </PropertyGroup>

@ryzngard
Copy link
Contributor

ryzngard commented Oct 6, 2021

Could this also be done with editorconfig? Would love to know thoughts on that. Here's my immediate thinking on for/against

Pros:

  • editorconfig already supports hierarchy in file system, and could even do file globbing to apply namespace
  • Could easily be plugged in on the Roslyn side (each document would be able to lookup property associated with it and just work)
  • Puts setting close to files if it differs from defined root

Cons:

  • Could be confusing since root/default namespace are project level settings
  • How would variables work? Could it be something like $(DefaultNamespace).Services?
    • Might be able to provide multiple settings like dotnet_namespace_prefix, dotnet_namespace, dotnet_namespace_affix with special values for current_folder_name etc.

@AlexeiScherbakov
Copy link

Editorconfig is a bad idea, because:

  1. Editorconfig is designed for code style rules, not code itself
  2. Final solution must control naming fules for every folder in one project - for editorconfig you need place new editorconfig file in every folder.

@ryzngard
Copy link
Contributor

ryzngard commented Oct 6, 2021

Editorconfig is designed for code style rules, not code itself

Yes. Namespace enforcement is a codestyle in csharp. I'll get into the details a bit below, but the only place RootNamespace has any meaning for a compiler (in dotnet) is in Visual Basic (maybe F#? not sure). Setting a property in csproj for namespaces will not change the symbol information for the project, nor will it break the compilation without extra tooling (IDE or Analyzers in this case). The output dll will always be the same regardless of what you set that property to.

Long Explanation

I'm assuming we're talking about Default Namespace and not Root Namespace. Just work with me on this definition, because I know it contradicts the naming convention in csproj

  • Default Namespace is a namespace that exists as the default. It has no impact beyond specifying what namespace a file is when created. Arguably could be the default if no namespace is specified, but I didn't check that yet (it may actually be)
  • Root Namespace is a namespace that precedes all namespaces.

A good example is the following code in VB:

Imports System

Namespace MyNamespace

    Module Program
        Sub Main(args As String())
            Console.WriteLine(GetType(Program).FullName)
        End Sub
    End Module
End Namespace

with the following vbproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>TestVB.Changed</RootNamespace>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

</Project>

The output of this is TestVB.Changed.MyNamespace.Program.

A similar C# example looks different:

namespace Test
{
    class Program 
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(typeof(Program).FullName);
        }
    }
}

with csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <RootNamespace>MyNamespace</RootNamespace>
  </PropertyGroup>

</Project>

The output is Test.Program. For C#, root namespace is purely a coding style convention and not impactful on the compilation of the code. It's not a root at all, it's just a hint to developer tools to "do the right thing".

Even in the original ask it was pointed out that this would impact new file creation:

Then if we create MyClass2 under MyFolder, the created class will be under the MyProject namespace instead of MyProject.MyFolder.

Code style is applied on new file creation. That's how we get the default namespace to start with. it also impacts things like file header. Even dotnet new doesn't have a single csharp class template, which is probably good considering that it would likely differ from the behavior of whatever IDE is being used.

Enforcement of namespace styling already exists for csharp in editorconfig with dotnet_style_namespace_match_folder , which uses a codestyle analyzer to indicate if a namespace is "correct". For better or worse, csharp has no real concept of a compile time "root" for namespaces beyond "global::". It's unfortunate the csproj property is called RootNamespace. In project property pages we even reword to Default Namespace

@AlexeiScherbakov
Copy link

Example:
You have namespace ViewModel, and folders inside it: Train,Truck,Plane, Utils.
Classes inside Train,Truck,Plane folders must be in *.ViewModel namespace. Classes inside Utils must be in *.ViewModel.Utils namepspace. How can this be achived with editorconfig?

@ryzngard
Copy link
Contributor

ryzngard commented Oct 6, 2021

Classes inside Train,Truck,Plane folders must be in *.ViewModel namespace. Classes inside Utils must be in *.ViewModel.Utils namepspace. How can this be achived with editorconfig?

It can't currently, which is why I bring this up. But also it can't be achieved with the current proposal afaik. Current proposal only addresses new files being created. There's no enforcement in csharp as a language that namespaces must be something specific. There's two parts to this:

  • dotnet_style_namespace_match_folder : this enforces namespace names based on folder structure. This is still under that purview, even if it doesn't let you customize the expectation currently. This results in IDE0130 diagnostic, which can be set to info/warning/error as desired.
  • If we added another setting in editorconfig such as dotnet_root_namespace and dotnet_namespace_suffix (naming is hard late at night) then the scenario would be as follows.

Root .editorconfig

dotnet_style_namespace_match_folder = true
dotnet_root_namespace = "MyRoot"

Root/{Train, Truck, Plane} Folder .editorconfig

[Utils/*.cs]
dotnet_namespace_suffix = "ViewModel.Utils"

[*.cs]
dotnet_namespace_suffix = "ViewModel"

  • assume my glob pattern is correct. I didn't look up editorconfig globs and it's late here.

I will also concede that this could be done with proposal + analyzer, if we update the analyzer to use the project properties proposed. I'm just not sure it's the best approach and think being explicit about namespace requirements as a style belongs in editorconfig. The downside of current proposal is that it's nontrivial for an analyzer to determine what the correct namespace is. Analyzers are how we would enforce this, so it should be considered for the proposal.

@drewnoakes
Copy link
Member

The design here should also factor in how we tool this from within Visual Studio. For folder level constructs, it would feel natural to surface this preference in the Properties pane when the folder in question is focussed in Solution Explorer. The default place to store metadata on folders would be on a <Folder> item in the project file. The Project System could pass these items to Roslyn.

@TwoPintOhh
Copy link

Maybe it would it would best just to have virtual folders. I also think adding the ability to just nest files would be great.

@julealgon
Copy link

Maybe it would it would best just to have virtual folders.

I'm also starting to think that this might be the cleaner approach here: have a different type of structure (virtual folder instead of "normal folder") that could also be potentially shown using a different graphic in the solution, and that would naturally not contribute to namespace segments.

The only caveat that I'm not sure how to solve, would be to allow this while not bloating the csproj files with those folders... Ideally, there should be a way to configure the logic used to automatically include files and folders to also include these "virtual folders" based on some criteria that the user can manipulate.

My use case is as follows (cropped sample):
image

I use the folders inside "Operations" as an organization tool alone, and I don't want those folders to exist in the namespaces of the classes inside. This structure has as many subfolders as there are "operations" in the system, which are modeled using command handlers.

It would be nice if there was a way to configure that "I want operation subfolders to be virtual" and then every time I add a folder in there, it is automatically set to virtual without further csproj modifications.

The proposal here, of adding metadata to a Folder element to either set a specific namespace or to not participate in namespaces, would solve my problem but would still require a high maintenance level since every new operation would require an extra change in the csproj.

Another way to support my scenario would be to have an option to "stop participating in namespaces from here", which would extend the "don't participate in namespaces" logic to all subfolders. That might be a little too specific of an option however.

@drewnoakes
Copy link
Member

The proposal here, of adding metadata to a Folder element to either set a specific namespace or to not participate in namespaces, would solve my problem but would still require a high maintenance level since every new operation would require an extra change in the csproj

Maybe something like this could avoid that maintenance:

<Folder Update="Operations/**/" ContributesToNamespace="False" />

We'd need to verify whether MSBuild's globbing can match folders, or only files.

@davkean
Copy link
Member

davkean commented Mar 23, 2022

MSBuild has no representation of folders. VS itself has an item that it uses to represent empty folders (such as <Folder Include="Properties" />) but not for folders containing source files, they are synthesized.

@viktorz
Copy link

viktorz commented Mar 30, 2022

What about introducing a new project-level property instead?
In my experience I usually want to avoid folder names becoming part of the namespace for the whole project or even for the whole solution. Project-level property flag solves the first case, same flag in Directory.Build.props solves the second.
Example property name DeriveTypeNamespaceFromPhysicalFolderStructure with possible values true/false

@julealgon
Copy link

julealgon commented Mar 30, 2022

What about introducing a new project-level property instead?
In my experience I usually want to avoid folder names becoming part of the namespace for the whole project or even for the whole solution. Project-level property flag solves the first case, same flag in Directory.Build.props solves the second.
Example property name DeriveTypeNamespaceFromPhysicalFolderStructure with possible values true/false

I'm not particularly fond of this option. To me, the existing warning is usually good (or in other words, "a good default"), but I want to opt-out of it in a few special situations.

A global flag just turns all of it off completely and this can lead into developers messing up a lot of stuff in namespaces.

I'd not be completely opposed to a global flag though assuming there exists a way to still configure this in a more granular fashion.

@salmelo
Copy link

salmelo commented May 25, 2022

This feature would be very useful for Unity development. Files in a Unity project have to be inside the Assets folder, and by convention code goes inside a Scripts folder, which leads to visual studio wanting to put all your classes in the very unhelpful Root.Assets.Scripts namespace.

@rjgotten
Copy link

rjgotten commented Jul 13, 2022

Continuing from the previous case with Operations -- how about just adopting folder semantics wholesale, using relative path operators . and .. ?

I.e. something like:

<!-- Everything; all children and grand-children remaining in the current namespace: -->
<Folder Update="Operations/**/" Namespace="." />

<!-- Skipping any contribution to the namespace by the children only: -->
<Folder Update="Operations/*/" Namespace="." />

<!-- Erase the parent namespace for the direct children: -->
<Folder Update="Operations/*/" Namespace="../*" />

<!--
  Renames the ConfirmReservation segment to Confirm but keeps all the parents as they were.
  I.e. the final namespace is {RootNamespace}.Operations.Confirm
-->
<Folder Update="Operations/ConfirmReservation/" Namespace="./Confirm" />

<!--
  Drops everything and just sets a completely new absolute namespace
  I.e. AndNow.ForSomething.CompletelyDifferent
-->
<Folder Update="Operations/ConfirmReservation/" Namespace="AndNow.ForSomething.CompletelyDifferent" />

<!--
  Or rooting it in front of RootNamespace:
  I.e. {RootNamespace}.AndNow.ForSomething.CompletelyDifferent
-->
<Folder Update="Operations/ConfirmReservation/" Namespace="/AndNow.ForSomething.CompletelyDifferent" />

Some of those are probably superfluous, being each other's duals - e.g. skipping the parent itself with . vs skipping back up from the children with ../* - , but that's the downside of going all in on the mental model of namespaces-as-folders and folder-like traversal.

@restush
Copy link

restush commented Jun 21, 2023

I want to ask something like this, but google direct me here.
Really need this kind of feature for Unity.

@InspiringCode
Copy link

Such feature would be extremely valuable to us too. Without this feature you usually get a very scattered and highly divided namespace structure. If you manually adjust namespace, you can be sure that the next dev doesn't too the same and you have a fragmented and meaningless namespace structure all over again... :(

@Matt-17
Copy link

Matt-17 commented Nov 27, 2023

I'm also interested in this feature, as I never thought about this is a ReSharper thing. But sometimes having trouble with created namespaces in new files and infos of wrong namespaces should have made me think about.

Anyway, I like the idea of keeping the metadata in project files. There is already a Folder item, which can (in my naive thinking) easily get an attribute. So deleting this item must be prohibited, when an item gets inserted into this folder.

Also to not make it overcomplicated, I would suggest starting with just a feature of similar property NamespaceProvider=false.

As those suggestions are good to enhance it, I would also vote for the Namespace attribute, as it will be more flexible.

Somehow I have two ideas, one looks like rjgotten and would be like

    <!-- this is default value and adds default namespace-->
    <Folder Include="MyFolder\" Namespace="." /> 

    <!-- this does not contribute to namespace and takes parent -->
    <Folder Include="MyFolder\" Namespace=".." /> // 

This behavior is like filesystem, which makes it a bit familiar but confuses maybe with namespaces.

My other idea would be:

    <!-- this is default the value and uses default namespace for this folder -->
    <Folder Include="MyFolder\" Namespace=".*" />
    <!-- this line will also be removed automatically, if it was empty and a file was added to that folder -->

    <!-- this folder does not contribute to namespace and uses parent namespace -->
    <Folder Include="MyFolder\" Namespace="." /> 

So in a further enhancement it could be extended with following:

    <!-- this is the explicit version of ".*" and will keep the namespace when renaming the folder -->
    <Folder Include="MyFolder\" Namespace=".MyFolder" /> // 
    <!-- in summary, a leading period means a relative namespace -->

    <!-- wihtout a leading perion, this will create complete new namespace root for this folder and subfolders -->
    <Folder Include="MyFolder\" Namespace="NewFolder" /> 

For my personal thinking the first step would be already a huge improvement.

@Kuurama
Copy link

Kuurama commented Jun 28, 2024

Not being able to specify a default namespace to a folder (therefore impacting child classes) makes some things hard.
Especially when messing around with libs that execute things via namespace ordering, which makes either the folder structure indented, or with flat folders like this: A, A.B, A.B.C, which is hum, quite sad in my opinion.

@dustinlacewell
Copy link

This is a frustrating property of Visual Studio's namespace handling. Your options are basically:

  • Folders are only a direct representation of your namespace, period.
  • You can use folders for other purposes, but, get no help automating namespaces whatsoever.

Is there a deal between JetBrains and Microsoft to keep this the status quo to drive sales to resharper? I'm kidding, but c'mon how do we live like this? :P

@CodeAngry
Copy link

@dustinlacewell Because they can afford to (somehow) take years before they add a very basic nothing in the tooling. It's been literally 5 years since this was opened...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Triage-Approved Reviewed and prioritized
Projects
None yet
Development

No branches or pull requests