我有一个程序,它查看源代码,查找方法,并对每个方法内部的代码执行一些计算。我正在尝试使用正则表达式来执行此操作,但这是我第一次在C#中使用它们而且我在测试结果时遇到了困难。
如果我使用此正则表达式来查找方法签名:
((private)|(public)|(sealed)|(protected)|(virtual)|(internal))+([a-z]|[A-Z]|[0-9]|[\s])*([\()([a-z]|[A-Z]|[0-9]|[\s])*([\)|\{]+)
然后通过此方法拆分源代码,将结果存储在字符串数组中:
string[] MethodSignatureCollection = regularExpression.Split(SourceAsString);
这会得到我想要的东西,即包含其中代码的方法列表吗?
答案 0 :(得分:9)
我强烈建议您使用Reflection(如果合适)或CSharpCodeProvider.Parse(...)
(根据rstevens推荐)
编写一个适用于所有情况的正则表达式可能非常困难。
以下是您必须处理的一些案例:
public /* comment */ void Foo(...) // Comments can be everywhere
string foo = "public void Foo(...){}"; // Don't match signatures in strings
private __fooClass _Foo() // Underscores are ugly, but legal
private void @while() // Identifier escaping
public override void Foo(...) // Have to recognize overrides
void Foo(); // Defaults to private
void IDisposable.Dispose() // Explicit implementation
public // More comments // Signatures can span lines
void Foo(...)
private void // Attributes
Foo([Description("Foo")] string foo)
#if(DEBUG) // Don't forget the pre-processor
private
#else
public
#endif
int Foo() { }
备注:强>
Split
方法会丢弃它匹配的所有内容,因此您实际上会丢失所有正在拆分的“签名”。{...}
可以嵌套,您当前的正则表达式可能会消耗更多{
using
语句,属性,注释,enum
定义,属性)可以显示在代码中,所以只是因为某些东西介于两个方法签名之间不会使它成为方法体的一部分。答案 1 :(得分:3)
使用CSharpCodeProvider.Parse()可能是一种更好的方法,可以将C#源代码“编译”到CompileUnit中。 然后,您可以遍历该编译单元中的名称空间,类型,类和方法。
答案 2 :(得分:1)
使用ICSharpCode.NRefactory.CSharp;
PM> install-package ICSharpCode.NRefactory
var parser = new CSharpParser();
var syntaxTree = parser.Parse(File.ReadAllText(sourceFilePath));
var result = syntaxTree.Descendants.OfType<MethodDeclaration>()
.FirstOrDefault(y => y.NameToken.Name == methodName);
if (result != null)
{
return result.ToString(FormattingOptionsFactory.CreateSharpDevelop()).Trim();
}
答案 3 :(得分:0)
不,这些访问修饰符还可以用于内部类和字段等。您需要编写一个完整的C#解析器才能使其正确。
你可以使用反射做你想做的事。尝试以下内容:
var methods = typeof (Foo).GetMethods();
foreach (var info in methods)
{
var body = info.GetMethodBody();
}
这可能有你计算所需的东西。
如果您需要原始的C#源代码,则无法通过反射获取它。不要编写自己的解析器。使用现有的here。
答案 4 :(得分:0)
我认为,使用正则表达式工作是可行的,但是这需要非常仔细地查看C#语言的规范并深入理解C#语法,这不是一个简单的问题。我知道你已经说过要将这些方法存储为字符串数组,但可能还有其他东西。已经指出要使用反射,但如果不能做到你想要的,你应该考虑使用ANTLR(另一种语言识别工具)。 ANTLR确实有C#语法可用。