从 .cs 文件中获取所有变量
Get all variables from .cs file
我想从一个 CS 文件中获取所有变量。 CS 文件将由我的应用程序打开,其代码将被读入字符串。在此之后我想将所有变量(包括名称)放入数组或列表中。之后需要在同一代码中找到这些变量,并将它们的名称替换为 MD5 散列值。 This 文章并没有真正帮助我,因为您无法从 "stringed" 代码中获取变量。我知道,这听起来很奇怪,但我真的需要帮助
这应该可以帮助您开始使用 Roslyn 的语法 API 和 C# 内置分析器。您需要将 "Microsoft.CodeAnalysis.CSharp" nuget 包添加到您的项目中。
假设您有一个源文件,您已将其解析为如下所示的字符串:
public class Person
{
public string Name { get; set; }
internal string Age;
int _val;
public void DoSomething(string x) { int y = 1; var z = 2; }
}
你可以这样写一些代码:
var parser = new ClassParser(stringOfCode);
var members = parser.GetMembers();
foreach (var m in members)
Console.WriteLine(m);
要输出这样的文本,向您显示 class 的所有已定义属性和字段的文本和位置(开始和长度),以便您可以根据需要替换名称:
Name: Name (36, 4), Type: string (29, 6), Declaration: public string Name { get; set; } (22, 32)
Name: Age (71, 3), Type: string (64, 6), Declaration: internal string Age; (55, 20)
Name: _val (80, 4), Type: int (76, 3), Declaration: int _val; (76, 9)
为了简化逻辑,您可以先定义一些 classes 来模拟结果并覆盖 ToString()
输出:
public class Member
{
public string KindText { get; set; }
public MemberToken NameToken { get; set; }
public MemberToken TypeToken { get; set; }
public MemberToken DeclarationToken { get; set; }
public override string ToString() => $"Name: {this.NameToken}, Type: {this.TypeToken}, Declaration: {this.DeclarationToken}";
}
public class MemberToken
{
public string Name { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public MemberToken(string code, TextSpan span)
{
this.Name = code.Substring(span.Start, span.Length);
this.Start = span.Start;
this.Length = span.Length;
}
public override string ToString() => $"{this.Name} ({this.Start}, {this.Length})";
}
然后你可以写一个CSharpSyntaxWalker
来访问你关心的节点(例如Field和属性声明),并将它们捕获到列表中:
public class MemberCollector : CSharpSyntaxWalker
{
public List<FieldDeclarationSyntax> Fields { get; } = new List<FieldDeclarationSyntax>();
public List<PropertyDeclarationSyntax> Properties { get; } = new List<PropertyDeclarationSyntax>();
public List<LocalDeclarationStatementSyntax> Variables { get; } = new List<LocalDeclarationStatementSyntax>();
public override void VisitFieldDeclaration(FieldDeclarationSyntax node) => this.Fields.Add(node);
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) => this.Properties.Add(node);
public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) => this.Variables.Add(node);
}
最后,你只需要编写你的class解析器来初始化语法树,然后分析语法树来识别成员。
public class ClassParser
{
public string Code { get; set; }
public SyntaxNode Root { get; set; }
public ClassParser(string code)
{
this.Code = code;
var tree = CSharpSyntaxTree.ParseText(code);
this.Root = tree.GetCompilationUnitRoot();
}
public List<Member> GetMembers()
{
var collector = new MemberCollector();
collector.Visit(this.Root);
var results = new List<Member>();
results.AddRange(collector.Properties.Select(p => new Member()
{
KindText = p.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, p.Span),
NameToken = new MemberToken(this.Code, p.Identifier.Span),
TypeToken = new MemberToken(this.Code, p.Type.Span),
}));
results.AddRange(collector.Fields.SelectMany(f => f.Declaration.Variables.Select(v => new Member()
{
KindText = f.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, f.Span),
TypeToken = new MemberToken(this.Code, f.Declaration.Type.Span),
NameToken = new MemberToken(this.Code, v.Span),
})));
results.AddRange(collector.Variables.SelectMany(f => f.Declaration.Variables.Select(v => new Member()
{
KindText = f.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, f.Span),
TypeToken = new MemberToken(this.Code, f.Declaration.Type.Span),
NameToken = new MemberToken(this.Code, v.Span),
})));
return results;
}
}
我想从一个 CS 文件中获取所有变量。 CS 文件将由我的应用程序打开,其代码将被读入字符串。在此之后我想将所有变量(包括名称)放入数组或列表中。之后需要在同一代码中找到这些变量,并将它们的名称替换为 MD5 散列值。 This 文章并没有真正帮助我,因为您无法从 "stringed" 代码中获取变量。我知道,这听起来很奇怪,但我真的需要帮助
这应该可以帮助您开始使用 Roslyn 的语法 API 和 C# 内置分析器。您需要将 "Microsoft.CodeAnalysis.CSharp" nuget 包添加到您的项目中。
假设您有一个源文件,您已将其解析为如下所示的字符串:
public class Person
{
public string Name { get; set; }
internal string Age;
int _val;
public void DoSomething(string x) { int y = 1; var z = 2; }
}
你可以这样写一些代码:
var parser = new ClassParser(stringOfCode);
var members = parser.GetMembers();
foreach (var m in members)
Console.WriteLine(m);
要输出这样的文本,向您显示 class 的所有已定义属性和字段的文本和位置(开始和长度),以便您可以根据需要替换名称:
Name: Name (36, 4), Type: string (29, 6), Declaration: public string Name { get; set; } (22, 32)
Name: Age (71, 3), Type: string (64, 6), Declaration: internal string Age; (55, 20)
Name: _val (80, 4), Type: int (76, 3), Declaration: int _val; (76, 9)
为了简化逻辑,您可以先定义一些 classes 来模拟结果并覆盖 ToString()
输出:
public class Member
{
public string KindText { get; set; }
public MemberToken NameToken { get; set; }
public MemberToken TypeToken { get; set; }
public MemberToken DeclarationToken { get; set; }
public override string ToString() => $"Name: {this.NameToken}, Type: {this.TypeToken}, Declaration: {this.DeclarationToken}";
}
public class MemberToken
{
public string Name { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public MemberToken(string code, TextSpan span)
{
this.Name = code.Substring(span.Start, span.Length);
this.Start = span.Start;
this.Length = span.Length;
}
public override string ToString() => $"{this.Name} ({this.Start}, {this.Length})";
}
然后你可以写一个CSharpSyntaxWalker
来访问你关心的节点(例如Field和属性声明),并将它们捕获到列表中:
public class MemberCollector : CSharpSyntaxWalker
{
public List<FieldDeclarationSyntax> Fields { get; } = new List<FieldDeclarationSyntax>();
public List<PropertyDeclarationSyntax> Properties { get; } = new List<PropertyDeclarationSyntax>();
public List<LocalDeclarationStatementSyntax> Variables { get; } = new List<LocalDeclarationStatementSyntax>();
public override void VisitFieldDeclaration(FieldDeclarationSyntax node) => this.Fields.Add(node);
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) => this.Properties.Add(node);
public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) => this.Variables.Add(node);
}
最后,你只需要编写你的class解析器来初始化语法树,然后分析语法树来识别成员。
public class ClassParser
{
public string Code { get; set; }
public SyntaxNode Root { get; set; }
public ClassParser(string code)
{
this.Code = code;
var tree = CSharpSyntaxTree.ParseText(code);
this.Root = tree.GetCompilationUnitRoot();
}
public List<Member> GetMembers()
{
var collector = new MemberCollector();
collector.Visit(this.Root);
var results = new List<Member>();
results.AddRange(collector.Properties.Select(p => new Member()
{
KindText = p.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, p.Span),
NameToken = new MemberToken(this.Code, p.Identifier.Span),
TypeToken = new MemberToken(this.Code, p.Type.Span),
}));
results.AddRange(collector.Fields.SelectMany(f => f.Declaration.Variables.Select(v => new Member()
{
KindText = f.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, f.Span),
TypeToken = new MemberToken(this.Code, f.Declaration.Type.Span),
NameToken = new MemberToken(this.Code, v.Span),
})));
results.AddRange(collector.Variables.SelectMany(f => f.Declaration.Variables.Select(v => new Member()
{
KindText = f.Kind().ToString(),
DeclarationToken = new MemberToken(this.Code, f.Span),
TypeToken = new MemberToken(this.Code, f.Declaration.Type.Span),
NameToken = new MemberToken(this.Code, v.Span),
})));
return results;
}
}