C# 使用正则表达式在源代码中查找方法

C# 使用正则表达式在源代码中查找方法,c#,regex,C#,Regex,我有一个程序,它查找源代码,查找方法,并对每个方法内部的代码执行一些计算。我正试图使用正则表达式来实现这一点,但这是我第一次在C#中使用它们,而且我很难测试结果 如果使用此正则表达式查找方法签名: ((private)|(public)|(sealed)|(protected)|(virtual)|(internal))+([a-z]|[A-Z]|[0-9]|[\s])*([\()([a-z]|[A-Z]|[0-9]|[\s])*([\)|\{]+) 然后使用此方法拆分源代码,将结果存储在字符

我有一个程序,它查找源代码,查找方法,并对每个方法内部的代码执行一些计算。我正试图使用正则表达式来实现这一点,但这是我第一次在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);

这能满足我的需求吗,比如一系列方法,包括其中的代码?

我强烈建议使用(如果合适)或(按照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
    方法将丢弃它匹配的所有内容,因此实际上,您将丢失正在拆分的所有“签名”
  • 不要忘记签名中可以有逗号
  • 如果可以嵌套,
    {…}
    ,则当前regexp消耗的
    {
    可能比它应该消耗的更多
  • 还有很多其他东西(预处理器命令,
    使用
    语句、属性、注释、
    enum
    定义、属性)可以显示在代码中,因此,仅仅因为某些东西位于两个方法签名之间,并不能使其成为方法体的一部分

不,这些访问修饰符还可以用于内部类和字段等。您需要编写完整的C#解析器才能正确使用

您可以使用反射执行任何操作。请尝试以下操作:

  var methods = typeof (Foo).GetMethods();
  foreach (var info in methods)
  {
    var body = info.GetMethodBody();
  }
这可能就是你计算所需要的


如果你需要原始的C#源代码,你无法通过反射获得。不要编写你自己的解析器。使用一个现有的解析器,如清单所示。

我想,使用正则表达式工作是可行的,但是这确实需要非常仔细地查看C#语言的规范,并深入理解C#语法,这是正确的不是一个简单的问题。我知道你说过你想把这些方法存储为字符串数组,但是大概还有一些东西超出了它。它已经被指出要使用反射,但是如果它不做你想要的,你应该考虑ANTLR(另一种语言识别工具)。.ANTLR确实有C#语法可用


使用CSharpCodeProvider.Parse()可能是一种更好的方法,它可以将C#源代码“编译”成编译器单元。
然后,您可以在该编译单元中遍历的名称空间、类型、类和方法。

使用
ICSharpCode.nreactory.CSharp;

PM>安装包ICSharpCode.nFactory

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();
}
var parser=new CSharpParser();
var syntaxTree=parser.Parse(File.ReadAllText(sourceFilePath));
var result=syntaxTree.subjects.OfType()的
.FirstOrDefault(y=>y.NameToken.Name==methodName);
如果(结果!=null)
{
返回result.ToString(formatingoptionsfactory.CreateSharpDevelop()).Trim();
}

实际上,普通正则表达式无法解决这个问题,因为它们不能计数。(不过,Perl“正则表达式”是图灵完备的。)