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);
            }
        }
    }
}

但是,当然,您必须检查所有类型和成员