Coding for fun: Write your code in comments with Roslyn
Sometimes, you have some very basic methods and you could find useless to comment them but sometimes you have to comment them in order to generate help file.
Some tools allow you to generate comments using the method signature.
For fun, I will use another way: I will write the method code in the comment.
I have a ConsoleApplication:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("a ?");
int a = int.Parse(Console.ReadLine());
Console.WriteLine("b ?");
int b = int.Parse(Console.ReadLine());
Console.WriteLine("{0} + {1} = {2}", a, b, Add(a, b));
Console.ReadLine();
}
/// <summary>
/// return a + b;
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static int Add(int a, int b)
{
throw new NotImplementedException();
}
}
The code of the Add method (return a + b;) is commented.
Now I will write my own C# compiler using Roslyn:
class Program
{
static void Main(string[] args)
{
string solutionPath = args[0];
string binaryDirectory = args[1];
var solution = Solution.Load(solutionPath);
List<IProject> notSortedProjects = solution.Projects.ToList();
List<IProject> projects = new List<IProject>();
do
{
foreach (IProject project in notSortedProjects.ToList())
{
if (project.ProjectReferences.All(prId => projects.Any(p => p.Id == prId)))
{
projects.Add(project);
notSortedProjects.Remove(project);
}
}
} while (notSortedProjects.Count != 0);
foreach (var project in projects)
{
foreach (var document in project.Documents)
{
var documentTree = document.GetSyntaxTree();
var newDocumentTree = new CodeInCommentsRewriter().Visit((SyntaxNode)documentTree.Root);
var newDocumentTreeText = new StringText(newDocumentTree.ToString());
solution = solution.UpdateDocument(document.Id, newDocumentTreeText);
}
using (var stream = new FileStream(string.Format("{0}.{1}",
Path.Combine(binaryDirectory, project.AssemblyName),
project.CompilationOptions.AssemblyKind == AssemblyKind.DynamicallyLinkedLibrary ? "dll" : "exe"), FileMode.Create))
{
var emitResult = solution.Projects.First(p => p.Id == project.Id).GetCompilation().Emit(stream);
if (!emitResult.Success)
throw new InvalidOperationException();
}
}
}
}
public class CodeInCommentsRewriter : SyntaxRewriter
{
protected override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
IEnumerator<SyntaxNode> bodySyntaxNodesEnumerator = node.BodyOpt.ChildNodes().GetEnumerator();
if (bodySyntaxNodesEnumerator.MoveNext())
{
ThrowStatementSyntax childNode = bodySyntaxNodesEnumerator.Current as ThrowStatementSyntax;
if (!bodySyntaxNodesEnumerator.MoveNext()// only one child node
&& childNode != null)
{
var comment = node.GetLeadingTrivia().Select(t => Regex.Match(t.GetText(), "return (.?)*").Value).FirstOrDefault(v => ! string.IsNullOrEmpty(v));
if (comment != null)
{
return Syntax.MethodDeclaration(
node.Attributes,
node.Modifiers,
node.ReturnType,
node.ExplicitInterfaceSpecifierOpt,
node.Identifier,
node.TypeParameterListOpt,
node.ParameterList,
node.ConstraintClauses,
Syntax.Block(
node.BodyOpt.OpenBraceToken,
Syntax.List(
Syntax.ParseStatement(comment)),
node.BodyOpt.CloseBraceToken),
node.SemicolonTokenOpt);
}
}
}
return base.VisitMethodDeclaration(node);
}
}
And here we are! // I use some shortcut (the code is a return in one line)
If I execute my compiler and then the generated exe, I can see in the Console that 1 + 2 = 3.