Как вы программно определяете количество ссылок на метод с помощью C#

StackOverflow https://stackoverflow.com/questions/106329

  •  01-07-2019
  •  | 
  •  

Вопрос

Недавно я унаследовал консольное приложение C #, которое нуждается в некоторой обрезке и очистке.Короче говоря, приложение состоит из одного класса, содержащего более 110 000 строк кода.Да, более 110 000 строк в одном классе.И, конечно же, приложение играет ключевую роль в нашем бизнесе, круглосуточно обновляя данные, используемые на динамичном веб-сайте.Хотя мне говорили, что мой предшественник был "действительно хорошим программистом", очевидно, что он совсем не разбирался в ООП (или контроле версий).

В любом случае...знакомясь с кодом, я нашел множество методов, которые объявлены, но на которые никогда не ссылаются.Похоже, что для версии кода использовалось копирование / вставка, например, скажем, у меня есть метод с именем getSomethingImportant(), скорее всего, существует другой метод с именем getSomethingImortant_July2007() (в большинстве случаев шаблоном является functionName_[datestamp]).Похоже, что когда программиста попросили внести изменения в getSomethingImportant(), он скопировал / вставил, затем переименовал в getSomethingImortant_Date, внес изменения в getSomethingImortant_Date, затем изменил все вызовы метода в коде на новое имя метода, оставив старый метод в коде, на который никогда не ссылались.

Я бы хотел написать простое консольное приложение, которое сканирует один огромный класс и возвращает список всех методов с указанием количества ссылок на каждый метод.По моим оценкам, существует более 1000 методов, так что выполнение этого вручную займет некоторое время.

Существуют ли классы в рамках .NET framework, которые я могу использовать для изучения этого кода?Или какие-либо другие полезные инструменты, которые могут помочь идентифицировать методы, которые объявлены, но на которые никогда не ссылаются?

(Побочный вопрос:Кто-нибудь еще когда-нибудь видел подобное приложение на C #, один очень большой класс?Это более или менее один огромный процедурный процесс, я знаю, что это первый, который я вижу, по крайней мере, такого масштаба.)

Это было полезно?

Решение

Вы могли бы попробовать использовать NDepend если вам просто нужно извлечь некоторую статистику о вашем классе.Обратите внимание, что этот инструмент основан на Mono.Cecil выполняет внутреннюю проверку сборок.

Другие советы

Скачать бесплатная пробная версия из Решарпера.Используйте Resharper-> Search->Find Usages в файле (Ctrl-Shift-F7), чтобы выделить все варианты использования.Кроме того, в строке состояния появится счетчик.Если вы хотите выполнить поиск по нескольким файлам, вы также можете сделать это с помощью Ctrl-Alt-F7.

Если вам это не нравится, выполните текстовый поиск по имени функции в Visual Studio (Ctrl-Shift-F), это должно подсказать вам, сколько вхождений было найдено в решении и где они находятся.

Для завершения Romain Verdier ответ, давайте немного углубимся в то, что NDepend может предложить вам здесь.(Отказ от ответственности:Я являюсь разработчиком команды NDepend)

NDepend позволяет запросить ваш .NET-код с помощью нескольких запросов LINQ.Узнать, какие методы вызываются какими другими, так же просто, как написать следующий запрос LINQ:

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

Результат этого запроса представлен таким образом, чтобы было легко просматривать вызывающих абонентов (и он на 100% интегрирован в Visual Studio).

NDepend methods callers and callees


Существует множество других возможностей NDepend, которые могут вам помочь.Например, вы можете щелкните правой кнопкой мыши метод в Visual Studio > NDepend> Выберите методы...> которые используют меня (прямо или косвенно) ...

NDepend Visual Studio method right click

Генерируется следующий запрос кода...

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 indirect method callers

А затем, нажав на кнопку Экспорт в график, вы получаете график вызовов вашего метода pivot (конечно, это может быть наоборот, т. е. метод, вызываемый прямо или косвенно определенным методом pivot).

NDepend call graph

Я не думаю, что вы захотите написать это сами - просто купите NDepend и использовать его Язык запроса кода

У FxCop есть правило, которое определяет неиспользуемые частные методы.Таким образом, вы могли бы пометить все методы закрытыми и заставить их сгенерировать список.

У FxCop также есть язык, если вы хотите стать более модным http://www.binarycoder.net/fxcop/

Если вы не хотите раскошеливаться на NDepend, поскольку это звучит так, как будто в одной сборке есть только один класс - закомментируйте методы и скомпилируйте.Если он скомпилируется, удалите их - у вас не возникнет никаких проблем с наследованием, виртуальными методами или чем-то подобным.Я знаю, это звучит примитивно, но иногда рефакторинг - это просто кропотливая работа, подобная этой.Это как бы предполагает, что у вас есть модульные тесты, которые вы запускаете после каждой сборки, пока не очистите код (красный / зеленый / рефакторинг).

Окно анализатора в Отражатель могу показать вам, где вызывается (используется) метод.
Однако, похоже, потребовалось бы очень много времени, чтобы получить информацию таким образом.
Вы могли бы взглянуть на API, который Reflector предоставляет для написания надстроек, и посмотреть, сможете ли вы таким образом выполнить основную работу по анализу.Я бы ожидал, что исходный код для надстройка для метрик кода мог бы немного рассказать вам о том, как получить информацию о методах из reflector API.

Редактировать:Кроме того, средство просмотра модели кода надстройка для Reflector тоже могла бы помочь.Это хороший способ изучить Reflector API.

Я не знаю ничего, что было бы создано для решения этого конкретного случая, но вы могли бы использовать Mono.Сесил.Отразите сборки, а затем подсчитайте ссылки в IL.Это не должно быть слишком сложно.

В самой .NET Framework нет простого инструмента для этого.Однако я не думаю, что вам действительно нужен список неиспользуемых методов сразу.На мой взгляд, вы просто пройдетесь по коду и для каждого метода проверите, не используется ли он, а затем удалите его, если да.Я бы использовал для этого команду Visual Studio "Найти ссылки".В качестве альтернативы вы можете использовать Resharper с его окном "Проанализировать".Или вы можете просто использовать инструмент анализа кода Visual Studio, чтобы найти все неиспользуемые частные методы.

Попробуйте, чтобы компилятор создавал файлы ассемблера, как в инструкциях 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", вы знаете, что у вас есть ссылка на функцию / метод.Этого может быть достаточно для ваших целей, но если нет, то потребуется всего несколько шагов, прежде чем вы сможете сгенерировать очень симпатичное дерево вызовов для всего вашего приложения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top