Nick Strupat
Nick Strupat

Reputation: 5063

Are there any tools that allow me to change all C# built-in types to their .NET Framework types?

One of the things that I find hard to keep consistent is the use of int vs Int32 and bool vs Boolean etcetera.

I find it simpler to identify all types by their case and color syntax highlighting...

List<int>

vs

List<Int32>

The latter is cleaner and upholds consistency. A lot of code is littered with both and I'm looking for a refactoring tool to change them all.

Are there any tools that allow me to change all C# built-in types to their .NET Framework types?

Upvotes: 1

Views: 321

Answers (4)

Nick Strupat
Nick Strupat

Reputation: 5063

I eventually wrote a macro to do this

Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics

Public Module ReplaceCSharpBuiltInTypesWithTheirFrameworkTypes
    Sub ReplaceCSharpBuiltInTypesWithTheirFrameworkTypes()
        Dim dictionary As New Collections.Generic.Dictionary(Of String, String)
        dictionary.Add("bool", "Boolean")
        dictionary.Add("byte", "Byte")
        dictionary.Add("sbyte", "SByte")
        dictionary.Add("char", "Char")
        dictionary.Add("decimal", "Decimal")
        dictionary.Add("double", "Double")
        dictionary.Add("float", "Single")
        dictionary.Add("int", "Int32")
        dictionary.Add("uint", "UInt32")
        dictionary.Add("long", "Int64")
        dictionary.Add("ulong", "UInt64")
        dictionary.Add("object", "Object")
        dictionary.Add("short", "Int16")
        dictionary.Add("ushort", "UInt16")
        dictionary.Add("string", "String")
        For Each key In dictionary.Keys
            DTE.Find.FindWhat = key
            DTE.Find.ReplaceWith = dictionary(key)
            DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument
            DTE.Find.MatchCase = True
            DTE.Find.MatchWholeWord = True
            DTE.Find.MatchInHiddenText = False
            DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral
            DTE.Find.ResultsLocation = vsFindResultsLocation.vsFindResultsNone
            DTE.Find.Action = vsFindAction.vsFindActionReplaceAll
            DTE.Find.Execute()
        Next
    End Sub
End Module

Upvotes: 0

user7116
user7116

Reputation: 64098

Using the Roslyn CTP, the following appears to work in practice:

static SyntaxTree UpdatePredefinedTypes(this SyntaxTree tree)
{
    PredefinedTypeSyntax node;
    var root = tree.Root;
    while (null != (node = root.DescendentNodes()
                               .OfType<PredefinedTypeSyntax>()
                               .FirstOrDefault(
                                 syn => redefineMap.ContainsKey(syn.PlainName))))
    {
        var ident = Syntax.IdentifierName(redefineMap[node.PlainName]);
        root = root.ReplaceNode<SyntaxNode, SyntaxNode>(
            node, 
            ident.WithLeadingTrivia(node.GetLeadingTrivia())
                 .WithTrailingTrivia(node.GetTrailingTrivia()));
    }

    return SyntaxTree.Create(
        tree.FileName,
        (CompilationUnitSyntax)root,
        tree.Options);
}

When using a proper redefineMap (e.g. {"int","Int32"}, {"double","Double"}) the following program was converted successfully:

using System;
namespace HelloWorld {
    class Program {
        static void Main(string[] args) {
            int x = Int32.Parse("11");
            double y = x;
            Console.WriteLine("Hello, World! {0}", y);
        }
     }
}

Output:

using System;
namespace HelloWorld {
    class Program {
        static void Main(String[] args) {
            Int32 x = Int32.Parse("11");
            Double y = x;
            Console.WriteLine("Hello, World! {0}", y);
        }
     }
}

When compiling:

var mscorlib = new AssemblyFileReference(
    typeof(object).Assembly.Location);

var newTree = UpdatePredefinedTypes(tree);

var compilation = Compilation.Create("HelloWorld")
                             .AddReferences(mscorlib)
                             .AddSyntaxTrees(new[] { newTree });
var results = compilation.Emit(File.Create("helloworld.exe"));
Console.WriteLine("Success: {0}", results.Success);
foreach (var message in results.Diagnostics)
{
    Console.WriteLine("{0}", message);
}
// C:\tmp\cs>roslyn-test.exe
// Success: True
// 
// C:\tmp\cs>dir /b *.exe
// roslyn-test.exe
// helloworld.exe
//
// C:\tmp\cs>helloworld.exe
// Hello, World! 11
//

You can even utilize the Workspace features to update an entire solution:

var workspace = Workspace.LoadSolution(info.FullName);
var solution = workspace.CurrentSolution;
foreach (var project in solution.Projects
    .Where(prj => prj.LanguageServices.Language == "C#"))
{
    foreach (var doc in project.Documents
        .Where(d => d.SourceCodeKind == SourceCodeKind.Regular
                 && d.LanguageServices.Language == "C#"))
    {
        var tree = SyntaxTree.ParseCompilationUnit(
            doc.GetText(),
            doc.DisplayName);
        var newTree = UpdatePredefinedTypes(tree);

        solution = solution.UpdateDocument(doc.Id, newTree.Text);
    }
}

workspace.ApplyChanges(workspace.CurrentSolution, solution);
// when running this in VS on itself it correctly updates the project!

Upvotes: 2

James Michael Hare
James Michael Hare

Reputation: 38427

If you look at StyleCop, rule SA1121 actually enforces the opposite of what you want (asks you to change Int32 to int). It's fairly trivial to decompile that rule and create your own StyleCop rule to enforce the opposite.

This isn't automatic, but after you do your initial conversion, you can incorporate it into your builds and then flag any new uses as errors.

Upvotes: 4

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112537

I do not know any tools except the search and replace function of VS.

I usually use the c# alias for type declarations and the .NET type when I call static members

int i = Int32.Parse(s);

It is just a personal preference.

Upvotes: 1

Related Questions