2009-04-07 2 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

На самом деле, обычные регулярные выражения не может решить эту проблему, потому что они не могут рассчитывать. (Perge «regexes», конечно, являются Turing.) – RossFabricant

3

Может быть, это лучший подход использовать CSharpCodeProvider.Parse(), который может «компилировать» C# исходный код в CompileUnit. Затем вы можете пройти через пространства имен, типы, классы и методы этого модуля компиляции.

+0

+1 для CSharpCodeProvider –

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(); 
} 
Смежные вопросы