正如标题所说,我想找到Roslyn的所有字符串,并能够操纵它们。我已经创建了一个程序,可以获取所有类和本地声明,但我希望有一些方法可以提取字符串。
在最佳世界中,我希望能够为以下字符串获取键值对,并避免使用int i = 0;
和var i2 = 0;
。
var test = "test";
string test1 = "testing";
String test2 = "testing 2";
我现在有什么:
{
class Program
{
static void Main(string[] args)
{
var workspace = MSBuildWorkspace.Create();
SyntaxTree tree = CSharpSyntaxTree.ParseText(
@"using System;
using System.Collections;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
var test = ""test"";
string test1 = ""testing"";
String test2 = ""testing 2"";
int i = 0;
var i2 = 0;
}
}
}");
var root = (CompilationUnitSyntax)tree.GetRoot();
var classVisitor = new ClassVirtualizationVisitor();
classVisitor.Visit(root);
var classes = classVisitor.Classes;
var localDeclaration = new LocalDeclarationVirtualizationVisitor();
localDeclaration.Visit(root);
var localDeclarations = localDeclaration.LocalDeclarations;
}
}
class LocalDeclarationVirtualizationVisitor : CSharpSyntaxRewriter
{
public LocalDeclarationVirtualizationVisitor()
{
LocalDeclarations = new List<LocalDeclarationStatementSyntax>();
}
public List<LocalDeclarationStatementSyntax> LocalDeclarations { get; set; }
public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
{
node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node);
LocalDeclarations.Add(node);
return node;
}
}
class ClassVirtualizationVisitor : CSharpSyntaxRewriter
{
public ClassVirtualizationVisitor()
{
Classes = new List<ClassDeclarationSyntax>();
}
public List<ClassDeclarationSyntax> Classes { get; set; }
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
node = (ClassDeclarationSyntax)base.VisitClassDeclaration(node);
Classes.Add(node); // save your visited classes
return node;
}
}
}
示例程序:
using System;
using System.Collections;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
var test = "test";
string test1 = "testing";
String test2 = "testing 2";
int i = 0;
var i2 = 0;
}
}
}
使用Strings v2.53
中的SysInternals
我会在.exe
下面得到以下字符串,我想从Roslyn那里获得相同的信息。
https://docs.microsoft.com/sv-se/sysinternals/downloads/strings
!This program cannot be run in DOS mode.
.text
`.rsrc
@.reloc
BSJB
v4.0.30319
#Strings
#US
#GUID
#Blob
T.#]
<Module>
mscorlib
HelloWorld
DebuggableAttribute
TargetFrameworkAttribute
CompilationRelaxationsAttribute
RuntimeCompatibilityAttribute
ObfuscationConsoleApp.exe
System.Runtime.Versioning
Program
System
Main
ObfuscationConsoleApp
.ctor
System.Diagnostics
System.Runtime.CompilerServices
DebuggingModes
args
Object
test
testing
testing 2
z\V
WrapNonExceptionThrows
.NETFramework,Version=v4.6.1
FrameworkDisplayName
.NET Framework 4.6.1
RSDS
g1M
|EF\R}
C:\Users\Oscar\source\repos\ObfuscationConsoleApp\ObfuscationConsoleApp\obj\Debug\ObfuscationConsoleApp.pdb
_CorExeMain
mscoree.dll
VS_VERSION_INFO
VarFileInfo
Translation
StringFileInfo
000004b0
FileDescription
FileVersion
0.0.0.0
InternalName
ObfuscationConsoleApp.exe
LegalCopyright
OriginalFilename
ObfuscationConsoleApp.exe
ProductVersion
0.0.0.0
Assembly Version
0.0.0.0
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
答案 0 :(得分:3)
非常感谢@MarcGravell和http://roslynquoter.azurewebsites.net/上的服务(请务必选中“保留冗余API调用”复选框)或https://github.com/KirillOsenkov/RoslynQuoter。
打印字符串键值对的最终代码:
var localDeclaration = new LocalDeclarationVirtualizationVisitor();
localDeclaration.Visit(root);
var localDeclarations = localDeclaration.LocalDeclarations;
foreach (var localDeclarationStatementSyntax in localDeclarations)
{
foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
{
var stringKind = variable.Initializer.Value.Kind();
if (stringKind == SyntaxKind.StringLiteralExpression)
{
Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
}
}
}
答案 1 :(得分:0)
基于公认的答案,这对我有帮助:
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace CodeScanner
{
class StringsCollector : CSharpSyntaxWalker
{
public List<String> _strings = new List<string>();
public override void VisitLiteralExpression(LiteralExpressionSyntax node)
{
if (node.IsKind(SyntaxKind.StringLiteralExpression))
{
// StringLiteralToken stringLiteralToken = node.Token;
// Console.WriteLine(node.Token.Value);
_strings.Add((string) node.Token.Value);
}
}
}
class Program
{
const string programText =
@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace TopLevel
{
using Microsoft;
using System.ComponentModel;
namespace Child1
{
using Microsoft.Win32;
using System.Runtime.InteropServices;
class Foo { }
}
namespace Child2
{
using System.CodeDom;
using Microsoft.CSharp;
class Bar {
public string test = ""str1\n\t"";
public void test()
{
Console.WriteLine(""str2"");
}
}
}
}";
private const string _rootDir = @"<replace here with your root dir>";
static List<string> GetAllCSharpCode(string folder)
{
List<string> result = new List<string>();
result.AddRange(Directory.GetFiles(folder, "*.cs"));
foreach (var directory in Directory.GetDirectories(folder).Where(d => !SkipDirectory(d)))
{
result.AddRange(GetAllCSharpCode(directory));
}
return result;
}
private static string[] skippedDirs = new string[] {"obj", "packages"};
static bool SkipDirectory(string directory)
{
var lcDir = directory.ToLower();
return skippedDirs.Any(sd => directory.EndsWith("\\" + sd));
}
static void Main(string[] args)
{
//PrintStrings(GetStrings(programText));
//Console.WriteLine("Hello World!");
var allCSharpFiles = GetAllCSharpCode(_rootDir);
PrintStrings(allCSharpFiles);
allCSharpFiles.ForEach(f =>
{
Console.WriteLine(f);
PrintStrings(GetStrings(File.ReadAllText(f)));
});
}
static void PrintStrings(List<string> list)
{
list.ForEach(Console.WriteLine);
}
private static List<string> GetStrings(string sourceCode)
{
SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode);
CompilationUnitSyntax root = tree.GetCompilationUnitRoot();
var collector = new StringsCollector();
collector.Visit(root);
return collector._strings;
}
}
}
当然可以对代码进行调整,以满足其他要求。