C# to format (indent, align) C# properly
Asked Answered
H

5

8

We have a code generator that munges the schema of a given database to automate our inhouse n-tier architecture. The output is various C# partial classes, one per file.

In the code to munge all the strings, we try and keep on top of the indenting and formatting as much as possible, but invariably when you come to open the file in Visual Studio the formatting is awry. A quick ctrl-k, ctrl-d fixes it, but obviously this reformatting is lost the next time the class is generated.

What I'd like to know, is if there's a way I can somehow automatically format the contents of the textfile in the same way Visual Studio does?

Pseudocode

Create "code" object, passing text file to constructor
Invoke "format" method
Re-save text file

Any help greatly appreciated.

EDIT: I should clarify - I want to be able to invoke the formatting from my C# code that creates the textfile containing my generated C#. The format of the code can be standardised (doesn't have to be per-developer), and I don't want to have to install any 3rd-party apps.

I seem to remember there's a namespace containing loads of classes for creating C# in C#: http://msdn.microsoft.com/en-us/library/system.codedom(VS.80).aspx, but I'm not sure if it contains any classes that could help.

FURTHER EDIT: My code generator is a winforms app deployed via a click-once install. It's used by many developers in-house. I need a solution that doesn't require each developer to have a tool installed on their machine.

Hydroid answered 25/3, 2009 at 13:7 Comment(0)
L
9

To properly indent code programmatically you would need Microsoft.CodeAnalysis.CSharp nuget package and .NET framework 4.6+. Sample code:

public string ArrangeUsingRoslyn(string csCode) {
    var tree = CSharpSyntaxTree.ParseText(csCode);
    var root = tree.GetRoot().NormalizeWhitespace();
    var ret = root.ToFullString();
    return ret;
}

One-liner:

csCode = CSharpSyntaxTree.ParseText(csCode).GetRoot().NormalizeWhitespace().ToFullString();

You may also use NArrange to sort methods in your cs file, organize usings, create regions, etc. Note that NArrange does not indent anything.

Labrie answered 7/11, 2017 at 8:5 Comment(4)
Nice answer, 8.5 years later.... :) The code generator I was asking about was .NET 2.0 I seem to remember.Hydroid
I have had the same issue recently and googled up your questions and a couple of others. - There were no up-to-date answers at all, so I have had to write one.Labrie
i got an error "'SyntaxNode' does not contain a definition for 'NormalizeWhitespace' and the best extension method overload 'SyntaxExtensions.NormalizeWhitespace(SyntaxToken, string, string, bool)' requires a receiver of type 'SyntaxToken"Seduce
@KarthicG It took me AGES to work this out, as I was having the same problem - adding "using Microsoft.CodeAnalysis" at the top of my class made it go away, it must be an extension method in there that works with SyntaxNode.Gardal
A
6

Take a look at Narrange.You'll probably need to automate these things as part of the build.
Not sure if it meets all your requirements though.
To quote:

NArrange is a .NET code beautifier that automatically organizes code members and elements within .NET classes.

Anywheres answered 25/3, 2009 at 13:20 Comment(4)
Thanks for the answer, but this won't help me as I'd like to format the code from my code.Hydroid
I love NArrange. NArrange is called from the command line, so you can call it from the codeColy
Wouldn't it require me to have it installed on the machine I'm running the code on, or is there a redistributable dll I can include in my app? Thanks.Hydroid
Source is available, so you should be able to integrate and redistribute. If you do, be sure to comply with the licenseColy
M
1

You can use CodeDOM and the CSharpCodeProvider. It is all in the namespaces Microsoft.CSharp and System.CodeDom.

Her is an example of a property:

StringWriter writer = new StringWriter();
CSharpCodeProvider provider = new CSharpCodeProvider();
CodeMemberProperty property = new CodeMemberProperty();
property.Type = new CodeTypeReference(typeof(int));
property.Name = "MeaningOfLifeUniverseAndEverything";
property.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(42)));
provider.GenerateCodeFromMember(property, writer, null);
Console.WriteLine(writer.GetStringBuilder().ToString());

This code will generate:

private int MeaningOfLifeUniverseAndEverything {
    get {
        return 42;
    }
}

The CodeDOM is a quite chatty way to generate code. The good thing is that you can generate multiple languages. Perhaps you can find a Erlang.NET CodeProvider?

You might be able to do a few shortcuts by using CodeSnippetExpression.

Megilp answered 25/3, 2009 at 13:41 Comment(2)
Hi Hallgrim. Yes, I discounted this way of generating code because of its verbosity. Without re-writing our code generator, there's not much I can do. Do you know if there's a method in System.CodeDom to format a class file?Hydroid
CSharpCodeProvider had a CreateParser() method, but it never returned anything but null and is now obsolete.Megilp
E
0

Only if you're running the code generator as a VS add-on - each developer is going to have different settings.

Eddi answered 25/3, 2009 at 13:10 Comment(1)
No, it's a winforms app. Thanks anyway.Hydroid
W
0

Here's how to do it from the context of a macro or add-in:

var dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.8.0");
dte.ExecuteCommand("File.OpenFile", filename);
dte.ExecuteCommand("Edit.FormatDocument", filename);
dte.ActiveDocument.Close(vsSaveChanges.vsSaveChangesYes);

Warning: As @Greg Hurlman says, the output will vary depending on the user's current options.

Edit:

unfortunately your method requires me to have an instance of VS running alongside my winforms app. Can you think of a way to create an instance of VS from within my app (if that's even possible)?

I think it might be possible to do from within your Win.Form app. However, you'll have to have Visual Studio installed on the machine running the code.

Try this:

var dte = (EnvDTE80.DTE2)Microsoft.VisualBasic.Interaction.CreateObject("VisualStudio.DTE.8.0", "");
dte.ExecuteCommand("File.OpenFile", filename);
dte.ExecuteCommand("Edit.FormatDocument", filename);
dte.ActiveDocument.Close(vsSaveChanges.vsSaveChangesYes);

Keep in mind that you'll need references to the EnvDTE80.dll assembly.

Winters answered 25/3, 2009 at 13:37 Comment(1)
Hi Randolpho - You're the closest one yet, but unfortunately your method requires me to have an instance of VS running alongside my winforms app. Can you think of a way to create an instance of VS from within my app (if that's even possible)? Thanks.Hydroid

© 2022 - 2024 — McMap. All rights reserved.