cref - Reflejo C#y encontrar todas las referencias
remarks c# (6)
Consideraría reflejar los ensamblajes de Visual Studio y ver si puede encontrarlo en la base de código de ingeniería inversa. Creo que VS realmente está navegando por el código en lugar de reflexionar. La reflexión, como ha publicado Michael, es excelente para determinar los bits de un conjunto, pero no los consumidores de esos bits. Sin embargo, no he reexaminado la reflexión para confirmar mis sospechas.
Dado un archivo DLL, me gustaría poder encontrar todas las llamadas a un método dentro de ese archivo DLL. ¿Cómo puedo hacer esto?
Esencialmente, ¿cómo puedo hacer programáticamente lo que ya hace Visual Studio?
No quiero usar una herramienta como .NET Reflector para hacer esto, pero la reflexión es buena y probablemente necesaria.
Consulte Pregunta de desbordamiento de pila Obtenga una lista de funciones para un archivo DLL .
Extraído de lo anterior (gracias Jon Skeet):
Para un ensamblado en particular, puede usar Assembly.GetTypes para obtener los tipos, luego para cada tipo, escriba Type.GetMethods (), Type.GetProperties () etc, o simplemente Type.GetMembers ().
Sin embargo, para la funcionalidad de los complementos, generalmente es una buena idea tener una interfaz común que los complementos deben implementar, lo que reduce la cantidad de reflejos que necesita usar. Use Type.IsAssignableFrom () para verificar si un tipo es compatible con una interfaz en particular.
Es posible que también quiera consultar el Marco de Extensibilidad Administrado que puede facilitar la implementación de un sistema de extensión.
La reflexión por sí sola no es suficiente para encontrar todas las referencias a un método en un conjunto determinado. Reflection le proporciona una matriz de bytes para el cuerpo de cualquier método en particular ( MethodInfo.GetMethodBody.GetILAsByteArray ) y usted mismo debe analizar las referencias a otros métodos. Hay varias bibliotecas de "lectores CIL " públicamente disponibles (no las he usado; espero que alguien publique más en ellas).
Agregar la opción FxCop : dependiendo de su escenario, puede reutilizar la lógica de análisis CIL proporcionada por FxCop (análisis de código Visual Studio) y agregar sus reglas personalizadas si ejecutarla como parte del análisis de código es correcto para usted.
Oye, este es un ejemplo, suponiendo que quieres buscar todas las llamadas en el ensamblado actual. Codifiqué esto tratando de obtener un valor de parámetro para establecer algunas restricciones para un método con algunos valores predeterminados. Pero no pude obtener los valores de los parámetros, solo obtuve los tipos y los valores predeterminados.
var currentAssembly = Assembly.GetExecutingAssembly();
foreach (var method in currentAssembly.GetTypes().Where(type => type.IsClass)
.SelectMany(cl => cl.GetMethods())
.OfType<MethodBase>()
.SelectMany(mb => mb.GetInstructions())
.Select(inst => inst.Operand).OfType<MethodInfo>()
.Where(mi => mi.Name == "<YourMethodName>"))
{
//here are your calls.
}
Espero eso ayude.
Puede echar un vistazo al artículo de MSDN Magazine Cómo determinar el ensamblado .NET y las referencias de métodos .
Para averiguar dónde se utiliza un método MyClass.Foo()
, debe analizar todas las clases de todos los ensamblados que tengan una referencia al ensamblaje que contiene MyClass
. Escribí una simple prueba de concepto de cómo se puede ver este código. En mi ejemplo, utilicé esta biblioteca (es solo un archivo .cs ) escrito por Jb Evain:
Escribí una pequeña clase de prueba para analizar:
public class TestClass
{
public void Test()
{
Console.WriteLine("Test");
Console.Write(10);
DateTime date = DateTime.Now;
Console.WriteLine(date);
}
}
Y escribí este código para imprimir todos los métodos utilizados en TestClass.Test()
:
MethodBase methodBase = typeof(TestClass).GetMethod("Test");
var instructions = MethodBodyReader.GetInstructions(methodBase);
foreach (Instruction instruction in instructions)
{
MethodInfo methodInfo = instruction.Operand as MethodInfo;
if(methodInfo != null)
{
Type type = methodInfo.DeclaringType;
ParameterInfo[] parameters = methodInfo.GetParameters();
Console.WriteLine("{0}.{1}({2});",
type.FullName,
methodInfo.Name,
String.Join(", ", parameters.Select(p => p.ParameterType.FullName + " " + p.Name).ToArray())
);
}
}
Me dio el siguiente resultado:
System.Console.WriteLine(System.String value);
System.Console.Write(System.Int32 value);
System.DateTime.get_Now();
System.Console.WriteLine(System.Object value);
Este ejemplo obviamente no está completo, porque no maneja los parámetros de ref y out, y no maneja argumentos genéricos. Estoy seguro de que olvidó otros detalles también. Simplemente muestra que se puede hacer.