Mono.Cecil 的参考汇编
Reference assembly by Mono.Cecil
例如我有一些 dll SomeLib
具有以下 类:
public class Class1
{
public Class2 GetClass2() => new Class2();
}
public class Class2
{
public int Prop1 { get; set; } = 5;
}
我读了 Mono.Cecil:
var sourceType = typeof(Class1);
var assemblyDefinition = AssemblyDefinition.ReadAssembly(sourceType.Module.FullyQualifiedName);
现在加载的程序集中有 Class1 和 Class2。
我想在此 "Mono.Cecil" 程序集中保留 Class1,但删除 Class2,只需通过引用从现有 SomeLib.dll
加载 Class2。
这是我的尝试。
它打印 5
。但是,如果我取消注释 //Delete Class2
部分,那么它将失败并出现异常。
static void Main(string[] args)
{
var sourceType = typeof(Class1);
var assemblyDefinition = AssemblyDefinition.ReadAssembly(sourceType.Module.FullyQualifiedName);
using (var stream = new MemoryStream())
{
var type = assemblyDefinition.MainModule.GetType(sourceType.FullName, true);
type.Name += "Custom";
assemblyDefinition.Name.Name += "Custom";
// Delete Class2
//var class2Type = assemblyDefinition.MainModule.Types.Single(t => t.FullName == typeof(Class2).FullName);
//assemblyDefinition.MainModule.Types.Remove(class2Type);
// Try to reference Class2's dll, SomeLib.dll
assemblyDefinition.MainModule.AssemblyReferences.Add(AssemblyNameReference.Parse(typeof(Class2).Assembly.FullName));
assemblyDefinition.Write(stream);
var assembly = Assembly.Load(stream.ToArray());
var newType = assembly.GetType(sourceType.FullName + "Custom");
var instance = Activator.CreateInstance(newType);
var method = newType.GetMethod(nameof(Class1.GetClass2));
var class2 = method.Invoke(instance, new object[0]);
var prop = class2.GetType().GetProperty(nameof(Class2.Prop1));
Console.WriteLine(prop.GetValue(class2));
}
Console.ReadLine();
}
只是给出正确答案 - 这是可能的。就像 Evk
说的,你可以只替换所有对 Class2 的引用,像这样
_typeRef = assemblyDefinition.MainModule.ImportReference(typeof(Class2));
static void Visit(MethodDefinition method)
{
if (method.ReturnType.FullName == _typeRef.FullName)
{
method.ReturnType = _typeRef;
}
for (var i = 0; i < method.Parameters.Count; i++)
{
if (method.Parameters[i].ParameterType.FullName == _typeRef.FullName)
{
method.Parameters[i].ParameterType = _typeRef;
}
}
foreach (var cmd in method.Body.Instructions)
{
if (cmd.OpCode == OpCodes.Call || cmd.OpCode == OpCodes.Callvirt)
{
var methodDefinition = ((MethodReference) cmd.Operand).Resolve();
if (methodDefinition.Module == _typeRef.Module)
{
Visit(methodDefinition);
}
}
}
}
但是,当然,您必须检查所有类型和成员
例如我有一些 dll SomeLib
具有以下 类:
public class Class1
{
public Class2 GetClass2() => new Class2();
}
public class Class2
{
public int Prop1 { get; set; } = 5;
}
我读了 Mono.Cecil:
var sourceType = typeof(Class1);
var assemblyDefinition = AssemblyDefinition.ReadAssembly(sourceType.Module.FullyQualifiedName);
现在加载的程序集中有 Class1 和 Class2。
我想在此 "Mono.Cecil" 程序集中保留 Class1,但删除 Class2,只需通过引用从现有 SomeLib.dll
加载 Class2。
这是我的尝试。
它打印 5
。但是,如果我取消注释 //Delete Class2
部分,那么它将失败并出现异常。
static void Main(string[] args)
{
var sourceType = typeof(Class1);
var assemblyDefinition = AssemblyDefinition.ReadAssembly(sourceType.Module.FullyQualifiedName);
using (var stream = new MemoryStream())
{
var type = assemblyDefinition.MainModule.GetType(sourceType.FullName, true);
type.Name += "Custom";
assemblyDefinition.Name.Name += "Custom";
// Delete Class2
//var class2Type = assemblyDefinition.MainModule.Types.Single(t => t.FullName == typeof(Class2).FullName);
//assemblyDefinition.MainModule.Types.Remove(class2Type);
// Try to reference Class2's dll, SomeLib.dll
assemblyDefinition.MainModule.AssemblyReferences.Add(AssemblyNameReference.Parse(typeof(Class2).Assembly.FullName));
assemblyDefinition.Write(stream);
var assembly = Assembly.Load(stream.ToArray());
var newType = assembly.GetType(sourceType.FullName + "Custom");
var instance = Activator.CreateInstance(newType);
var method = newType.GetMethod(nameof(Class1.GetClass2));
var class2 = method.Invoke(instance, new object[0]);
var prop = class2.GetType().GetProperty(nameof(Class2.Prop1));
Console.WriteLine(prop.GetValue(class2));
}
Console.ReadLine();
}
只是给出正确答案 - 这是可能的。就像 Evk
说的,你可以只替换所有对 Class2 的引用,像这样
_typeRef = assemblyDefinition.MainModule.ImportReference(typeof(Class2));
static void Visit(MethodDefinition method)
{
if (method.ReturnType.FullName == _typeRef.FullName)
{
method.ReturnType = _typeRef;
}
for (var i = 0; i < method.Parameters.Count; i++)
{
if (method.Parameters[i].ParameterType.FullName == _typeRef.FullName)
{
method.Parameters[i].ParameterType = _typeRef;
}
}
foreach (var cmd in method.Body.Instructions)
{
if (cmd.OpCode == OpCodes.Call || cmd.OpCode == OpCodes.Callvirt)
{
var methodDefinition = ((MethodReference) cmd.Operand).Resolve();
if (methodDefinition.Module == _typeRef.Module)
{
Visit(methodDefinition);
}
}
}
}
但是,当然,您必须检查所有类型和成员