reflection - Mono.Cecil AddInterfaceImplementation 等效?
问题描述
我正在研究 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 等效项或解决方法以及如何使用它?
解决方案
这可以通过以下方式实现:
- 迭代程序集中定义的所有类型
- 检查哪些类型应用了该属性
- 注入方法。
例如,您可以执行以下操作:
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 功能。
推荐阅读
- sql - 根据字段值删除 Hana 表上的值
- vb.net - VB.NET 使用 Delegate 添加任何 EventHandler 类型
- reactjs - 为什么`tslint`报告`TS2531:对象可能是'null'。'即使我在使用前检查过?
- javascript - 彼此上方的两个画布返回不同的 x,y 坐标
- c# - 由于字符串 id,CRUD Edit 无法检索数据
- python - 使用 After The Deadline 拼写检查器似乎返回空列表
- mysql - SQL 注入 我安全吗?
- spring-boot - asciidoctorj 库不适用于 Spring Boot 2 可执行引导 jar
- html - Blogger Soho 主题页眉图片没有覆盖完整的页眉宽高
- javascript - 正则表达式匹配包含“apple”但不匹配同一字符串中的“orange”的字符串