Ответ 1
Вы можете сделать это с помощью Mono.Cecil.
Вот простая LINQPad программа, которая демонстрирует:
const string AssemblyFilePath = @"path\to\assembly.dll";
void Main()
{
var assembly = ModuleDefinition.ReadModule(AssemblyFilePath);
var calls =
(from type in assembly.Types
from caller in type.Methods
where caller != null && caller.Body != null
from instruction in caller.Body.Instructions
where instruction.OpCode == OpCodes.Call
let callee = instruction.Operand as MethodReference
select new { type, caller, callee }).Distinct();
var directRecursiveCalls =
from call in calls
where call.callee == call.caller
select call.caller;
foreach (var method in directRecursiveCalls)
Debug.WriteLine(method.DeclaringType.Namespace + "." + method.DeclaringType.Name + "." + method.Name + " calls itself");
}
Здесь будут выводиться методы, которые вызывают непосредственно. Обратите внимание, что я обработал только инструкцию Call, я не уверен, как правильно обращаться с другими инструкциями по вызову здесь, или даже если это возможно.
Caveat: обратите внимание, что это будет, потому что я обрабатывал только одну команду только для работы со статически скомпилированными вызовами.
Виртуальные вызовы, вызовы через интерфейсы, которые просто возвращаются к тому же методу, не будут обнаружены этим, для этого необходим намного более продвинутый код.