2008-09-19 4 views
5

Ich habe vor kurzem geerbt C# -Konsolenanwendung, die einige Beschneidung benötigt und bereinigen. Kurz gesagt, die App besteht aus einer einzigen Klasse mit über 110.000 Codezeilen. Yup, über 110.000 Zeilen in einer einzigen Klasse. Und natürlich ist die App der Kern unseres Geschäfts und läuft rund um die Uhr, um Daten zu aktualisieren, die auf einer dynamischen Website verwendet werden. Obwohl mir gesagt wurde, dass mein Vorgänger "ein wirklich guter Programmierer" war, lag es auf der Hand, dass er OOP (oder Versionskontrolle) überhaupt nicht kannte.Wie programmgesteuert identifizieren Sie die Anzahl der Verweise auf eine Methode mit C#

Wie auch immer ... während ich mich mit dem Code vertraut mache, habe ich viele Methoden gefunden, die deklariert, aber nie referenziert werden. Es sieht so aus, als ob copy/paste verwendet wurde, um den Code zu versionieren, zum Beispiel habe ich eine Methode namens getSomethingImportant(), wahrscheinlich gibt es eine andere Methode namens getSomethingImmortant_July2007() (das Muster ist in den meisten Fällen funktionsName_ [datestamp]). Es sieht so aus, als wenn der Programmierer aufgefordert wurde, eine Änderung an getSomethingImportant() vorzunehmen, dann copy/paste, dann getSomethingImmortant_Date, Änderungen an getSomethingImortant_Date, dann alle Methodenaufrufe im Code auf den neuen Methodennamen ändern und die alte Methode beibehalten der Code, aber nie referenziert.

Ich möchte eine einfache Konsolen-App schreiben, die durch die eine riesige Klasse kriecht und eine Liste aller Methoden mit der Häufigkeit zurückgibt, mit der auf jede Methode verwiesen wurde. Nach meinen Schätzungen gibt es weit über 1000 Methoden, also würde es eine Weile dauern, dies manuell zu tun.

Gibt es Klassen innerhalb des .NET-Frameworks, die ich verwenden kann, um diesen Code zu untersuchen? Oder andere nützliche Tools, mit denen Sie Methoden identifizieren können, die deklariert, aber nie referenziert werden?

(Seitliche Frage: Hat jemand sonst jemals eine C# App wie diese gesehen, eine reeeealy große Klasse? Es ist mehr oder weniger ein riesiger prozeduraler Prozess, ich weiß, das ist das erste was ich gesehen habe, zumindest in dieser Größe.)

Antwort

12

Sie könnten versuchen, NDepend zu verwenden, wenn Sie nur einige Statistiken über Ihre Klasse extrahieren müssen. Beachten Sie, dass dieses Tool intern auf Mono.Cecil angewiesen ist, um Baugruppen zu überprüfen.

0

Ich weiß nichts, das für diesen speziellen Fall gebaut wird, aber Sie könnten Mono.Cecil verwenden. Reflektieren Sie die Assemblys und zählen Sie die Referenzen in der IL. Sollte nicht zu hart sein.

1

Ich glaube, Sie können das mit NDepend tun, aber ich habe es noch nie benutzt.

1

Der Analyzer-Fenster in Reflector kann Ihnen zeigen, verwenden, wo ein Verfahren (Used) genannt wird.
Klingt, als würde es sehr lange dauern, die Informationen auf diese Weise zu bekommen.
Sie können sich die API ansehen, die Reflector zum Schreiben von Add-Ins zur Verfügung stellt, und sehen, ob Sie auf diese Weise die grunzende Arbeit der Analyse erhalten. Ich würde erwarten, dass der Quellcode für die code metrics add-in Ihnen ein wenig darüber erzählen könnte, wie man Informationen über Methoden von der Reflektor-API erhält.

Edit: Auch das code model viewer Add-in für Reflektor könnte auch helfen. Es ist eine gute Möglichkeit, die Reflektor-API zu erkunden.

0

Es gibt kein einfaches Tool, das in .NET Framework selbst zu tun. Aber ich glaube nicht, dass Sie wirklich eine Liste von unbenutzten Methoden auf einmal brauchen. Wie ich es sehe, gehen Sie einfach durch den Code und für jede Methode überprüfen Sie, ob es nicht verwendet wird und löschen Sie es dann, wenn dies der Fall ist. Ich würde Visual Studio "Find References" Befehl verwenden, um das zu tun. Alternativ können Sie Resharper mit seinem "Analize" -Fenster verwenden.Oder Sie können das Visual Studio-Codeanalyse-Tool verwenden, um alle nicht verwendeten privaten Methoden zu finden.

+0

Ihr Vorschlag zu streichen, da ich durch den Code mein erster Gedanke war zu. Ich werde diese Methode plus NDepend verwenden, wie andere vorgeschlagen haben, um weitere Analysen durchzuführen. – Duffy

0

Können Sie das Geld für ReSharper bekommen? Es ist das ideale Werkzeug zum Refactoring.

3

Laden Sie die kostenlose Testversion von Resharper. Verwenden Sie den Resharper-> Search-> Usage in File suchen (Ctrl-Shift-F7), um alle Verwendungen markiert anzuzeigen. Außerdem wird in der Statusleiste eine Zählung angezeigt. Wenn Sie mehrere Dateien durchsuchen möchten, können Sie das auch mit Strg-Alt-F7 tun.

Wenn Sie das nicht mögen, suchen Sie nach dem Funktionsnamen in Visual Studio (Strg-Umschalt-F), dies sollte Ihnen sagen, wie viele Vorkommen in der Lösung gefunden wurden und wo sie sind.

0

Um Ihre "Nebenfrage" zu beantworten, habe ich noch nie einen so schlechten gesehen, kann ein guter Eintrag für The Daily WTF sein. Vielleicht nennen Sie es "Die ultimative Kopie/Paste-Wiederverwendung".

-1

Versuchen Sie, den Compiler Assembler-Dateien zu senden, wie in x86-Anweisungen, nicht .NET-Assemblys.

Warum? Weil es viel einfacher ist, Assembler-Code zu analysieren als C# -Code oder .NET-Assemblies.

Zum Beispiel kann eine Funktion/Methode Deklaration sieht wie folgt aus etwas:

.string "w+" 
    .text 
    .type create_secure_tmpfile, @function 
create_secure_tmpfile: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $24, %esp 
    movl $-1, -8(%ebp) 
    subl $4, %esp 

und Funktion/Methode Referenzen etwas wie folgt aussehen:

subl $12, %esp 
    pushl 24(%ebp) 
    call create_secure_tmpfile 
    addl $16, %esp 
    movl 20(%ebp), %edx 
    movl %eax, (%edx) 

Wenn Sie sehen, "create_secure_tmpfile:" Sie Sie wissen, dass Sie eine Deklaration der Funktion/Methode haben, und wenn Sie "call create_secure_tmpfile" sehen, wissen Sie, dass Sie eine Funktion/Methodenreferenz haben. Das ist vielleicht gut genug für Ihre Zwecke, aber wenn nicht, dann sind es nur noch ein paar Schritte, bevor Sie einen sehr niedlichen Anrufbaum für Ihre gesamte Anwendung erstellen können.

+0

Wie ist es "viel einfacher" Assembler zu analysieren, wenn .net Reflexionsbibliotheken enthält? Ganz zu schweigen von Drittanbieter-Bibliotheken wie Mono.Cecil. –

+0

Da es eine riesige Basis von Tools für die Verarbeitung von zeilenbasierten Daten auf eine Ad-hoc-Weise gibt. z.B. Grep, Sed, Awk usw. – mbac32768

1

FXCop verfügt über eine Regel, die nicht verwendete private Methoden identifiziert. Sie können also alle Methoden als privat markieren und eine Liste erzeugen lassen.

FXCop hat auch eine Sprache, wenn Sie ausgefallenere http://www.binarycoder.net/fxcop/

1

bekommen wollte Wenn Sie nicht wollen, berappen für NDepend, da es klingt wie es nur eine einzige Klasse in einer einzigen Baugruppe ist - Kommentar aus die Methoden und kompilieren. Wenn es kompiliert wird, löschen Sie sie - Sie werden keine Vererbungs-Probleme, virtuelle Methoden oder etwas ähnliches haben. Ich weiß, dass es primitiv klingt, aber manchmal ist das Refactoring nur eine Grunt-Arbeit wie diese. Dies setzt voraus, dass Sie Komponententests ausführen, die Sie nach jedem Build ausführen, bis Sie den Code bereinigt haben (Rot/Grün/Refaktor).

4

Um die Romain Verdier Antwort zu vervollständigen, lassen Sie ein wenig in was NDepend Ihnen hier bringen können. (Disclaimer: Ich bin ein Entwickler des NDepend-Teams)

NDepend können Sie Ihren .NET-Code mit einigen LINQ-Abfragen abfragen. Zu wissen, welche Methoden aufrufen und durch die andere genannt, ist so einfach wie das Schreiben der folgenden LINQ-Abfrage:

from m in Application.Methods 
select new { m, m.MethodsCalled, m.MethodsCallingMe } 

Das Ergebnis dieser Abfrage wird in einer Weise dargestellt, die Anrufern und Angerufenen einfach macht zu durchsuchen (und seine 100 % in Visual Studio integriert).

NDepend methods callers and callees


Es gibt viele andere NDepend Funktionen, die Ihnen helfen können. Zum Beispiel können Sie Recht vor, eine Methode in Visual Studio klicken> NDepend> Select Methoden ...>, die es (direkt oder indirekt) ...

NDepend Visual Studio method right click

Die folgende Code-Abfrage generiert wird, verwenden. ..

from m in Methods 
let depth0 = m.DepthOfIsUsing("NUnit.Framework.Constraints.ConstraintExpression.Property(String)") 
where depth0 >= 0 orderby depth0 
select new { m, depth0 } 

..., die mit der Tiefe der Anrufe direkt und indirekt Anrufer übereinstimmt, (1 bedeutet eine direkten Anrufer, 2 bedeuten Anrufer direkter Anrufer und so weiter).

NDepend indirect method callers

Und dann durch Anklicken der Schaltfläche Export in Graph, Sie einen Anruf Graph von Pivot-Methode bekommen (natürlich könnte es umgekehrt, dh Verfahren direkt oder indirekt von einem bestimmten genannt werden Pivot-Methode).

NDepend call graph

Verwandte Themen