Mono.Cecil AddInterfaceImplementation 等效?
Posted
技术标签:
【中文标题】Mono.Cecil AddInterfaceImplementation 等效?【英文标题】:Mono.Cecil AddInterfaceImplementation equivalent? 【发布时间】:2021-10-09 13:59:36 【问题描述】:我正在开发 Mono.Cecil codegen util,我想执行以下操作:
Loop through types
If type contains X attribute:
- Add ITestInterface implementation (where ITestInterface has defined some methods)
// For reference
public interface ITestInterface
void Something();
int IntSomething();
// Expected result, if type contains X attribute:
// Before codegen:
[X]
public class CodeGenExample
// After codegen
[X]
public class CodeGenExample : ITestInterface
public void Something()
// some stuff
public int IntSomething()
// do some stuff
return 0;
我看到 .NET Reflection 有一个 AddInterfaceImplementation 方法 (https://docs.microsoft.com/pl-pl/dotnet/api/system.reflection.emit.typebuilder.addinterfaceimplementation?view=net-5.0)。
是否有 Mono.Cecil 等效项或解决方法以及如何使用它?
【问题讨论】:
【参考方案1】:这可以通过以下方式实现:
-
迭代程序集中定义的所有类型
检查哪些类型应用了该属性
注入方法。
例如,您可以执行以下操作:
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace inject
interface IMyInterface
int Something();
class MarkerAttribute : Attribute
[Marker]
class Foo
class Program
static void Main(string[] args)
if (args.Length == 1)
using var a = AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location);
var interfaceToImplement = a.MainModule.GetType("inject.IMyInterface");
foreach(var t in a.MainModule.Types)
if (t.HasCustomAttributes && t.CustomAttributes.Any(c => c.Constructor.DeclaringType.Name == "MarkerAttribute"))
System.Console.WriteLine($"Adding methods to : t");
var something = new MethodDefinition("Something", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, a.MainModule.TypeSystem.Int32);
something.Body = new Mono.Cecil.Cil.MethodBody(something);
var il = something.Body.GetILProcessor();
il.Emit(OpCodes.Ldc_I4, 42);
il.Emit(OpCodes.Ret);
t.Methods.Add(something);
// Add the interface.
t.Interfaces.Add(new InterfaceImplementation(interfaceToImplement));
var path = typeof(Program).Assembly.Location + ".new";
a.Write(path);
System.Console.WriteLine($"Modified version written to path");
else
object f = new Foo();
IMyInterface itf = (IMyInterface) f;
System.Console.WriteLine($"Something() == itf.Something()");
另一个可能的解决方案是在内部类中实现方法并复制它们的方法体。
附带说明一下,您可以使用以下 2 个在线工具来探索/了解有关 CIL、Mono.Cecil、C# 的更多信息:
-
Sharplab.io
Cecilifier(免责声明:我是这篇文章的作者)
也就是说,如果您可以使用 C# 9.0,您或许可以利用新的 Source Generators feature。
【讨论】:
附加问题,这只添加了 Something() 方法。但是我需要一个 ITestInterface 实现,因为我想在 codegen 之后将该类传递给例如 StaticTestInvoker(ITestInterface test)。 对不起.. 完全忽略了接口实现位。我已经更新了答案以包含它。以上是关于Mono.Cecil AddInterfaceImplementation 等效?的主要内容,如果未能解决你的问题,请参考以下文章