2009-04-07 93 views
2

我有一個程序在源代碼中查找,查找方法並對每個方法內部的代碼執行一些計算。我試圖使用正則表達式來做到這一點,但這是我第一次在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); 

將這讓我得到我想要的東西,即方法列表,包括其中的代碼?

回答

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定義,屬性),可以在代碼中顯示,所以只是因爲兩個方法簽名之間的東西不會使它成爲方法體的一部分。
0

不,這些訪問修飾符也可以用於內部類和字段等等。你需要編寫一個完整的C#解析器才能正確使用它。

你可以用反射來做你想做的。請嘗試如下所示:

var methods = typeof (Foo).GetMethods(); 
    foreach (var info in methods) 
    { 
    var body = info.GetMethodBody(); 
    } 

這可能是您計算所需的。

如果您需要原始的C#源代碼,您無法通過反射來獲取它。不要編寫自己的解析器。使用現有的,列出here

0

我猜,使用正則表達式來實現某些工作是可行的,但是這確實需要仔細查看C#語言的規範以及對C#語法的深入瞭解,這不是一個簡單的問題。我知道你已經說過你想將這些方法存儲爲字符串數組,但大概還有其他的東西。已經指出要使用反射,但是如果這不符合你的要求,你應該考慮ANTLR(另一種語言識別工具)。 ANTLR確實有C#語法。

http://www.antlr.org/about.html

+0

其實,普通的正則表達式解決不了這個問題,因爲他們可以不計。 (儘管Perl是「正則表達式」,但Turing是完整的。) – RossFabricant 2009-04-07 17:56:20

3

也許這是一個較好的方法爲使用CSharpCodeProvider.Parse(),它可以「編譯」 C#源代碼轉換成一個CompileUnit。 然後,您可以遍歷該編譯單元中的命名空間,類型,類和方法。

+0

對於CSharpCodeProvider – 2009-04-07 18:14:39

1

使用ICSharpCode.NRefactory.CSharp;

PM>安裝包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(); 
}