How to know the content of variable using Roslyn?
-
02 Januari 2012 3:58
Hi,
Is it possible to know the content of a variable using Roslyn?
Thanks
Semua Balasan
-
02 Januari 2012 12:49
What exactly do you mean? Can you show an expample?
If you mean that you have a source code and you want to get contents of one specific variable at one specific point in the code, I think there's only one way to do that: actually run the code.
If that's what you want, then you could take the source code, use Roslyn to add a code to report the value, compile it and execute it.
-
03 Januari 2012 0:00
Hi svick,
Yes, that's exactly what I want.
So, I need to know what is the value of a particular variable at a certain point.
for example, if I have:
int total = 0;
for (int i=0; i<5; i++)
total += i;
then I like to know the content of "total" while it is in the loop or outside the loop.
I'll use this information to make an application that will perform like a black box testing for a certain program.
Is there any example about how to do all of your suggestion above?
Thanks
B.Hart- Diedit oleh b.hart 03 Januari 2012 0:01
-
03 Januari 2012 18:54
You could use Roslyn to rewrite the source and inject statements that would log the values. You would then need to compile the new source and run it. You could use Roslyn to build the compilation, emit it and load the assembly to run.
Wayward LINQ Lacky -
04 Januari 2012 0:23Pemilik
Below is a code example that shows one way to do what svick and Matt have suggested above -
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
class Program
{
static void Main()
{
var tree = SyntaxTree.ParseCompilationUnit(
@"using System;
class Program
{
static void Main(params string[] args)
{
int total = 0;
for (int i=0; i < 5; ++i)
{
total += i;
}
}
}");
var mscorlib = new AssemblyFileReference(typeof(object).Assembly.Location);
var origComp = Compilation.Create("Original",
references: new[] { mscorlib },
syntaxTrees: new[] { tree });
if (!HasErrors(origComp))
{
var rewriter = new Rewriter();
// Use rewriter to insert Console.WriteLine() statements.
// Format the resulting node so that the code is correctly indented.
var newRoot = (CompilationUnitSyntax)rewriter.Visit(tree.Root).Format();
// Uncomment below line to see the modified code.
// Console.WriteLine(newRoot.GetFullText());
var newTree = SyntaxTree.Create("New.cs", newRoot);
var newComp = Compilation.Create("New",
references: origComp.References,
syntaxTrees: new[] { newTree });
var output = Execute(newComp);
// You can now verify the output.
Console.WriteLine(output);
}
}
class Rewriter : SyntaxRewriter
{
// A rewriter that inserts a Console.WriteLine() statement to print the value of the
// LHS variable for every compound assignement statement encountered in the input tree.
protected override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node)
{
SyntaxNode retVal = null;
if (node.Expression.Kind == SyntaxKind.AddAssignExpression ||
node.Expression.Kind == SyntaxKind.SubtractAssignExpression ||
node.Expression.Kind == SyntaxKind.MultiplyAssignExpression ||
node.Expression.Kind == SyntaxKind.DivideAssignExpression)
{
// Print value of the variable on the 'Left' side of
// every compound assignement statement encountered.
var addAssignExpr = (BinaryExpressionSyntax)node.Expression;
var printValueStatement =
Syntax.ParseStatement("Console.WriteLine(" + addAssignExpr.Left.GetText() + ");");
retVal = Syntax.Block(statements: Syntax.List<StatementSyntax>(node, printValueStatement));
}
else
{
retVal = base.VisitExpressionStatement(node);
}
return retVal;
}
}
static bool HasErrors(Compilation comp)
{
var retVal = comp.GetDiagnostics().Any();
if (retVal)
{
Console.WriteLine("Compilation Errors:");
foreach (var diag in comp.GetDiagnostics())
{
Console.WriteLine(diag.ToString());
}
}
return retVal;
}
static string Execute(Compilation comp)
{
string output = string.Empty, exeFilename = "Output.exe";
var stream = new FileStream(exeFilename, FileMode.OpenOrCreate);
var emitResult = comp.Emit(stream);
stream.Close();
if (emitResult.Diagnostics.Any())
{
output += "Emit Errors:\n";
foreach (var diag in emitResult.Diagnostics)
{
output += diag.ToString() + "\n";
}
}
else
{
var p = Process.Start(
new ProcessStartInfo()
{
FileName = exeFilename,
UseShellExecute = false,
RedirectStandardOutput = true
});
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
return output.Trim();
}
}Hope this helps!
Shyam Namboodiripad | Software Development Engineer in Test | Roslyn Compilers Team- Ditandai sebagai Jawaban oleh b.hart 04 Januari 2012 1:48
-
04 Januari 2012 1:03Pemilik
Also, on a related note, while it is not possible to "know the content of a variable" it is possible to "know the content of constant expressions" using Roslyn.
The below example prints the value of all compile time constants and constant expressions in the supplied input code.
static void Main()
{
var tree = SyntaxTree.ParseCompilationUnit(
@"using System;
class Program
{
static void Main(params string[] args)
{
const int MIN = 10;
const int MAX = 100;
Console.WriteLine(MIN + MAX);
}
}");
var mscorlib = new AssemblyFileReference(typeof(object).Assembly.Location);
var comp = Compilation.Create("Original",
references: new[] { mscorlib },
syntaxTrees: new[] { tree });
var walker = new Walker() { CurrentSemanticModel = comp.GetSemanticModel(tree) };
walker.Visit(tree.Root);
}
class Walker : SyntaxWalker
{
public SemanticModel CurrentSemanticModel { get; set; }
public override void Visit(SyntaxNode node)
{
if (node is ExpressionSyntax)
{
var semanticInfo = CurrentSemanticModel.GetSemanticInfo((ExpressionSyntax)node);
if (semanticInfo != null && semanticInfo.IsCompileTimeConstant)
{
Console.WriteLine("Expression '" + node.GetText() + "' has value=" + semanticInfo.ConstantValue);
}
}
base.Visit(node);
}
}The output of the above program is as follows -
Expression '10' has value=10
Expression '100' has value=100
Expression 'MIN + MAX' has value=110
Expression 'MIN' has value=10
Expression 'MAX' has value=100
Shyam Namboodiripad | Software Development Engineer in Test | Roslyn Compilers Team -
04 Januari 2012 1:50
That's Awesome,
Thanks a lot Shyam for the example. It really helps.
Also thanks to Svick and Matt for the idea.
Cheers