【问题标题】:Reference assembly by Mono.CecilMono.Cecil 的参考汇编
【发布时间】:2018-03-02 09:24:00
【问题描述】:

例如,我有一些带有以下类的 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();
}

【问题讨论】:

  • 如果 Class2 正被 Class1 使用,如何删除它?
  • 我尝试通过引用SomeLib.dll 从文件中加载Class2。请参阅代码示例中的// Try to reference Class2's dll, SomeLib.dll
  • 但那是另一个 Class2。 SomeLibCustom 中的 Class1 使用 SomeLibCustom 中的 Class2。这与 SomeLib 中的 Class2 不同。他们有相同的名字这一事实并没有帮助。
  • 它们也具有相同的结构。我理解它,但正在寻找一种方法来说 SomeLibCustom 以使用 SomeLib.dll 中的Class2。看来我需要更改GetClass2 方法...
  • 是的,您需要替换所有对 Class2 的引用。

标签: c# .net cil mono.cecil


【解决方案1】:

只是为了提出正确的答案 - 这是可能的。就像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);
            }
        }
    }
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多