我有一个任务,我需要解析C#脚本并寻找某个方法属性并从中提取部分,我想知道是否有一种比我更优雅的方式:
[Info("Title", "Author", "5.2.5", ResourceId = 819)]
这是我做的:
// foreach line in script
if (line.Contains("[Info(") && line.Contains("ResourceId"))
{
var _attributes = line
.Replace(" ", "")
.Replace("\"", "")
.Replace("[Info(", "")
.Replace(")]", "")
.Replace("ResourceId=", "")
.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
// Do stuff with _attributes[0] _attributes[1] etc..
break;
}
Run Code Online (Sandbox Code Playgroud)
现在最简单的解决方案是使用Roslyn.您可以解析代码,查找实际属性(而不是看起来像您正在寻找的属性的东西),并以C#-proper的方式处理它们.
这是一个简单的例子:
var infoAttributes = CSharpSyntaxTree.ParseText(@"
namespace MyNamespace
{
public class SomeClass
{
const string SomeConstant = ""Hi!"";
[Info(""Some book"", ""Ray Brandenburg"", ""5.2.5"", ResourceId = 819)]
public void SomeMethod()
{
}
[InfoAttribute(SomeConstant, 42, ""Banana"")]
public void SomeMethod2()
{
}
// [Info(""Not going to happen"", ""Hilary Clinton"", ""1.2.0"")]
public void SomeMethod3()
{
}
}
}
")
.GetRoot()
.DescendantNodes()
.OfType<AttributeSyntax>()
.Where(i => i.Name.ToString() == "Info" || i.Name.ToString() == "InfoAttribute")
.Where
(
i =>
i.ArgumentList.Arguments.Count(j => j.NameEquals == null) == 3
&& i.ArgumentList.Arguments[0].GetFirstToken().IsKind(SyntaxKind.StringLiteralToken)
&& i.ArgumentList.Arguments[1].GetFirstToken().IsKind(SyntaxKind.StringLiteralToken)
&& i.ArgumentList.Arguments[2].GetFirstToken().IsKind(SyntaxKind.StringLiteralToken)
)
.Select
(
i =>
new
{
Title = (string)i.ArgumentList.Arguments[0].GetFirstToken().Value,
Author = (string)i.ArgumentList.Arguments[1].GetFirstToken().Value,
Version = (string)i.ArgumentList.Arguments[2].GetFirstToken().Value,
ResourceId =
i.ArgumentList.Arguments
.Where(j => j.NameEquals != null && j.NameEquals.Name.ToString() == "ResourceId")
.Select(j => j.ChildNodes().Skip(1).First().GetFirstToken().Value.ToString())
.FirstOrDefault()
}
);
infoAttributes.Dump();
Run Code Online (Sandbox Code Playgroud)
在这个级别,这只是解析源代码.为了使事情变得更简单,我添加了防御性条款,只使用字面值来实现这一点 - 你可能希望将它们变成警告,以便手动处理或者其他东西.代码正确处理任何琐事(例如空白),代码看起来像属性声明但不是,评论和许多其他可能的问题.还有一个简化的假设 - 值必须是文字(字符串或其他).该示例将只找到一个Info
属性 - 一个SomeMethod2
使用常量和不同的构造函数重载,并且一个on SomeMethod3
被注释掉.
另一个层次是从中创建一个编译树.这涉及更多,但允许您使一切工作,就像它是真正的C#代码 - 例如,属性SomeMethod2
将SomeConstant
正确解析.当然,如果你真的想要100%正确,这需要收集所有的依赖等,这听起来像是一种矫枉过正.除非这是您的代码中的真正问题,否则警告应该对异常值有效.如果在代码中经常使用局部常量,那么扩展代码以处理局部文字常量仍然非常容易.
作为免责声明,这肯定不是使用Roslyn进行解析的最佳方式.这只是我想到的第一件事,花了一段时间才开始.我几乎每天都在寻找更好的方式来处理Roslyn :)
归档时间: |
|
查看次数: |
108 次 |
最近记录: |