6

最近、プルーニングとクリーンアップが必要な C# コンソール アプリケーションを継承しました。簡単に言うと、このアプリは 110,000 行以上のコードを含む単一のクラスで構成されています。ええ、1 つのクラスで 110,000 行以上。そしてもちろん、アプリは私たちのビジネスの中核であり、動的な Web サイトで使用されるデータを 24 時間更新しています。私の前任者は「本当に優れたプログラマー」だったと言われていますが、OOP (またはバージョン管理) にまったく興味がなかったことは明らかです。

とにかく...コードに慣れているうちに、宣言されているが参照されていないメソッドがたくさん見つかりました。コードのバージョンを変更するためにコピー/貼り付けが使用されたように見えます。プログラマーが getSomethingImportant() に変更を加えるように依頼されたとき、彼はコピー/貼り付けして名前を getSomethingImortant_Date に変更し、getSomethingImortant_Date に変更を加えてから、コード内のすべてのメソッド呼び出しを新しいメソッド名に変更し、古いメソッドをそのままにしていたようです。コードですが、参照されることはありません。

1 つの巨大なクラスをクロールし、すべてのメソッドのリストと各メソッドが参照された回数を返す単純なコンソール アプリを作成したいと考えています。私の推定では、1000 をはるかに超えるメソッドがあるため、手動でこれを行うには時間がかかります。

このコードを調べるために使用できる .NET フレームワーク内のクラスはありますか? または、宣言されているが参照されていないメソッドを特定するのに役立つその他の便利なツールはありますか?

(補足質問: このような非常に大きなクラスの C# アプリを見た人は他にいますか? 多かれ少なかれ 1 つの巨大な手続き型プロセスです。少なくともこのサイズのものは、私が見たのはこれが初めてです。)

4

10 に答える 10

13

You could try to use NDepend if you just need to extract some stats about your class. Note that this tool relies on Mono.Cecil internally to inspect assemblies.

于 2008-09-19T23:22:35.590 に答える
6

Romain Verdierの回答を完成させるために、ここで NDepend がもたらすものを少し掘り下げてみましょう。(免責事項: 私は NDepend チームの開発者です)

NDepend を使用すると、いくつかの LINQ クエリを使用して .NET コードをクエリできます。どのメソッドがどのメソッドを呼び出し、どのメソッドによって呼び出されるかを知ることは、次の LINQ クエリを記述するのと同じくらい簡単です。

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

このクエリの結果は、呼び出し元と呼び出し先を簡単に参照できるように表示されます (また、Visual Studio に 100% 統合されています)。

NDepend メソッドの呼び出し元と呼び出し先


あなたを助けることができる他の多くの NDepend 機能があります。たとえば、Visual Studio でメソッドを右クリック > NDepend > メソッドの選択... > 私を (直接的または間接的に) 使用している...

NDepend Visual Studio メソッドの右クリック

次のコード クエリが生成されます...

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

...これは、直接および間接の発信者と、呼び出しの深さを一致させます (1 は直接の発信者を意味し、2 は直接の発信者の発信者を意味します)。

NDepend 間接メソッド呼び出し元

次に、[グラフにエクスポート] ボタンをクリックすると、ピボット メソッドのコール グラフが表示されます (もちろん、特定のピボット メソッドによって直接または間接的に呼び出されるメソッドなど、逆の場合もあります)。

NDepend コール グラフ

于 2008-10-26T17:29:30.923 に答える
4

Resharperの無料トライアルをダウンロードしてください。Resharper->Search->Find Usages in File (Ctrl-Shift-F7) を使用して、すべての使用箇所を強調表示します。また、ステータスバーにカウントが表示されます。複数のファイルを検索する場合は、Ctrl-Alt-F7 を使用して検索することもできます。

それが気に入らない場合は、Visual Studio (Ctrl-Shift-F) で関数名のテキスト検索を実行してください。これにより、ソリューションで見つかったオカレンスの数とその場所がわかります。

于 2008-09-19T23:42:44.793 に答える
1

NDependをシェルアウトしたくない場合は、単一のアセンブリに1つのクラスしかないように思われるため、メソッドをコメントアウトしてコンパイルします。コンパイルする場合は、それらを削除します。継承の問題や仮想メソッドなどは発生しません。原始的に聞こえるかもしれませんが、リファクタリングがこのようなうんざりするような作業になることもあります。これは、コードがクリーンアップされるまで(赤/緑/リファクタリング)、各ビルド後に実行する単体テストがあることを前提としています。

于 2008-09-22T22:01:16.477 に答える
1

FXCop には、未使用のプライベート メソッドを識別するルールがあります。したがって、すべてのメソッドをプライベートとしてマークし、リストを生成させることができます。

FXCopには、より洗練されたものにしたい場合の言語もあります http://www.binarycoder.net/fxcop/

于 2008-09-20T00:56:48.983 に答える
1

Reflectorのアナライザー ウィンドウには、メソッドが呼び出された場所 (使用者) が表示されます。
このように情報を取得するには、非常に長い時間がかかるように思えます。
アドインを作成するために Reflector が提供する API を見て、その方法で分析の単調な作業を行うことができるかどうかを確認してください。コード メトリクス アドインのソース コードから、リフレクター API からメソッドに関する情報を取得する方法について少し説明できると思います。

Edit: Also the code model viewer add-in for Reflector could help too. It's a good way to explore the Reflector API.

于 2008-09-19T23:28:28.667 に答える
1

There is no easy tool to do that in .NET framework itself. However I don't think you really need a list of unused methods at once. As I see it, you'll just go through the code and for each method you'll check if it's unused and then delete it if so. I'd use Visual Studio "Find References" command to do that. Alternatively you can use Resharper with its "Analize" window. Or you can just use Visual Studio code analysis tool to find all unused private methods.

于 2008-09-19T23:29:50.097 に答える
1

I don't think you want to write this yourself - just buy NDepend and use its Code Query Language

于 2008-09-19T23:23:16.557 に答える
0

この特定のケースを処理するために構築されたものは何も知りませんが、Mono.Cecil を使用できます。アセンブリを反映してから、IL 内の参照をカウントします。厳しすぎてはいけません。

于 2008-09-19T23:17:38.347 に答える
-1

.NET アセンブリではなく、x86 命令のように、コンパイラにアセンブラー ファイルを出力させてみてください。

なんで?C# コードや .NET アセンブリよりも、アセンブラー コードを解析する方がはるかに簡単だからです。

たとえば、関数/メソッドの宣言は次のようになります。

    .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

関数/メソッド参照は次のようになります。

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

"create_secure_tmpfile:" が表示されている場合は、関数/メソッドの宣言があることがわかります。また、"call create_secure_tmpfile" が表示されている場合は、関数/メソッドの参照があることがわかります。これは目的には十分かもしれませんが、そうでない場合は、アプリケーション全体の非常にかわいい呼び出しツリーを生成する前に、あと数ステップしかありません。

于 2008-09-20T00:17:24.757 に答える