1

I would like to migrate my projects to .NET 6 and C# 10. As a part of this migration I would like to use global using directives.

Has Visual Studio 2022 any tool or help to do a "to global using directive" refactoring?

Prasad Telkikar
  • 15,207
  • 5
  • 21
  • 44
g.pickardou
  • 32,346
  • 36
  • 123
  • 268

4 Answers4

2

I don't think, there is any tool which does "To global using" directive refactoring, but you can try alternate way,

  1. Replace using block with empty string in entire project, you can use Ctrl + Shift + H

enter image description here

  1. Now you can add global using in any .cs file or you put all global using in a separate file called globalusings.cs

Note:

  • Find + Replace will add additional empty line in all .cs files.
Prasad Telkikar
  • 15,207
  • 5
  • 21
  • 44
2

Making namespace global should render corresponding using unnecessary in other files. Remove unnecessary usings diagnostic allows you to select the scope for the fix:

enter image description here

If for some reason the diagnostic is not shown you can enable it via .editorconfig via rule code (IDE0005):

# IDE0005: Using directive is unnecessary.
dotnet_diagnostic.IDE0005.severity = suggestion
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • Many thx, that is a good idea, but the half of the story, I mean we must create the global usings manually. You are right, then a using directive removal cleanup (either VS build in via editorconfig, or 3rd party) will do the heavy lifting. – g.pickardou Nov 17 '21 at 06:55
  • @guru-stron Do you know when a using statement should be kept in a file instead of moved to `globalusings.cs`? Is there an advantage to not move everything into `globalusings.cs`? – surfmuggle Feb 06 '23 at 07:51
  • @surfmuggle you mean global usings? – Guru Stron Feb 06 '23 at 07:57
  • @guru-stron Yes. Are there any advantages to declare a `using foo.bar` statement as a global using statement and move it from `n` files to a central `globalusings.cs` other than to not have this `using foo.bar` in `n` files? – surfmuggle Feb 06 '23 at 08:05
  • @surfmuggle oh, you mean `using` vs `global using` (personally I even prefer adding `Using` xml element into csproj instead of `global using` in some file). The main advantage - reducing number of code lines with corresponding benefits - some are described in [this answer](https://stackoverflow.com/a/75170889/2501279). Despite IDEs being able to reduce the clutter of working with namespaces still there is some (and you do not always work with IDE - for example when looking at the diff in the github). – Guru Stron Feb 06 '23 at 08:28
2

I've just faced to the same problem and wrote simple console application to solve this problem.

using System.Text;

if (args.Length == 0 || string.IsNullOrEmpty(args[0]))
    throw new ArgumentException("You must specify directory");
var directoryForScan = args[0];
if (!Directory.Exists(directoryForScan))
{
    throw new ArgumentException($"{directoryForScan} not exist");
}

var filesEnumeration = Directory.EnumerateFiles(directoryForScan, "*.cs", SearchOption.AllDirectories);
var directorySeparator = Path.DirectorySeparatorChar;
var usingSet = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var filePath in filesEnumeration.Where(it => !it.Contains($"{directorySeparator}bin{directorySeparator}") 
                                                  && !it.Contains($"{directorySeparator}obj{directorySeparator}")))
{
    await ProcessUsingAsync(filePath, usingSet);
}

var resultFilePath = Path.Combine(directoryForScan,"GlobalUsings.cs");

await using var resultStream = new FileStream(resultFilePath, FileMode.Create, FileAccess.Write, FileShare.Write);
await using var writer = new StreamWriter(resultStream, Encoding.UTF8);
foreach (var item in usingSet)
{
    Console.WriteLine(item);
    await writer.WriteAsync("global ");
    await writer.WriteLineAsync(item);
}

await resultStream.FlushAsync();

static async Task ProcessUsingAsync(string filePath, ISet<string> usingSet)
{
    await using var fileStream = File.OpenRead(filePath);
    using var reader = new StreamReader(fileStream);
    string? currentLine;
    do
    {
        currentLine = await reader.ReadLineAsync();
        if (currentLine is not null 
            && currentLine.StartsWith("using")
            && currentLine.EndsWith(";") 
            && !currentLine.Contains(" static ") 
            && !currentLine.Contains("="))
        {
            usingSet.Add(currentLine);
        }
    } while (currentLine != null);
}
2

ReSharper/Jetbrains is again one step ahead with it's 'Extract Global Using refactoring'.

If you want to know more about it https://www.jetbrains.com/help/resharper/Refactorings__Extract_Global_Using.html

Lukáš Kmoch
  • 1,239
  • 11
  • 11