-
Notifications
You must be signed in to change notification settings - Fork 1
Mixin Reference
PCL.Mixin 命名空间直接位于 PCL.Core.dll。插件项目引用目标启动器版本的 PCL.Core.dll 后即可使用下列公共类型。
[Mixin(typeof(PublicTarget), Priority = 1200)]
internal static class PublicTargetMixin
{
}
[Mixin("PCL.InternalTarget", Optional = true)]
internal static class OptionalInternalMixin
{
}MixinAttribute:
| 成员 | 说明 |
|---|---|
Type target |
直接指定可引用的目标类型 |
string targetName |
使用完整类型名,在运行时从已加载程序集解析 |
Priority |
类型默认优先级,默认 1000
|
Optional |
此 Mixin 失败时只记录警告并继续 |
同一类型可以声明多个 [Mixin],但公共插件通常为每个目标类型创建独立 Mixin 类,便于定位日志。
Inject、Overwrite、Redirect、ModifyArg、ModifyArgs、ModifyVariable 和 ModifyConstant 都继承 MixinOperationAttribute。
| 成员 | 说明 |
|---|---|
Method |
目标方法名或 Name(Type1,Type2) 描述符 |
ArgumentTypes |
显式选择重载 |
Priority |
此处理器优先级,默认继承类型或配置优先级 |
Require |
最少匹配数,低于该值失败 |
Expect |
精确匹配数,不相等时失败 |
Allow |
最大匹配数,超过该值失败 |
也可以把匹配约束写成方法标记:
[Inject("Run", At = MixinAt.Invoke, Target = TargetCall)]
[Require(1), Expect(1), Allow(1), Priority(1500), Ordinal(0)]
private static void BeforeCall()
{
}若没有显式 Require,使用 Mixin 配置中的 injectors.defaultRequire,默认值为 1。
[Inject("Compute", At = MixinAt.Head, Cancellable = true)]
private static void Before([Arg(0)] int value, CallbackInfo<int> callback)
{
if (value < 0)
callback.SetReturnValue(40);
}
[Inject("Touch", At = MixinAt.Head), Cancellable]
private static void BeforeVoid([Arg(0)] int value, CallbackInfo callback)
{
if (value < 0)
callback.Cancel();
}CallbackInfo 提供:
-
Id:目标方法标识。 -
IsCancellable:是否允许取消。 -
IsCancelled:处理器是否已经取消。 -
Cancel():取消目标方法;未声明 Cancellable 时调用会抛出异常。
CallbackInfo<T> 额外提供:
-
ReturnValue:读取或修改当前返回值。 -
SetReturnValue(value):设置返回值并取消后续原方法执行。
可以在 [Inject] 上写 Cancellable = true,也可以在处理器上使用 [Cancellable]。
| 标记或类型 | 来源 |
|---|---|
[This] |
目标对象实例 |
[Arg(n)] |
第 n 个目标参数 |
[Local(n)] |
第 n 个局部变量 |
[Return] |
当前返回值 |
CallbackInfo / CallbackInfo<T>
|
注入控制对象 |
MethodBase / MethodInfo
|
当前目标方法 |
object[] |
目标参数数组 |
目标参数使用 ref 时可以写回。局部变量绑定必须设置:
[Inject("Run", At = MixinAt.Return, Locals = LocalCapture.FailSoft)]
private static void Capture([Local(0)] int value)
{
}LocalCapture:
| 值 | 行为 |
|---|---|
NoCapture |
默认;处理器出现 [Local] 时直接报错 |
FailSoft |
捕获失败时记录警告并跳过该注入 |
FailHard |
捕获失败时使 Mixin 应用失败 |
HEAD 尚未建立可捕获的局部变量。局部变量索引和类型都必须与目标 IL 一致。
Redirect 把指定方法调用、字段访问或其他受支持指令替换为处理器:
[Redirect("Compute", Target = "System.Math::Abs(System.Int32)")]
private static int KeepSign(int value) => value;字段读取示例:
[Redirect("Read", At = MixinAt.Field,
Target = "Example.Target::Value")]
private static int ReadTwice(Example.Target instance) => instance.Value * 2;处理器签名必须能替代原指令的栈输入和输出。错误的签名会在应用或调用阶段失败。
修改一个调用参数:
[ModifyArg("Run",
Target = "Example.Target::Twice(System.Int32)",
Index = 0)]
private static int Increment(int value) => value + 1;修改全部调用参数:
[ModifyArgs("Run",
Target = "Example.Target::Combine(System.Int32,System.Int32)")]
private static void Replace(MixinArgs args)
{
args.Set(0, 2);
args[1] = 3;
}MixinArgs 提供 Count、索引器、Get<T>、Set<T> 和返回副本的 ToArray()。
[ModifyVariable("Run", At = MixinAt.Load, Index = 0, Ordinal = 0)]
private static int ModifyLoadedValue(int value) => value + 10;
[ModifyConstant("GetLimit", Target = "int:10", Ordinal = 0)]
private static int Double(int value) => value * 2;常量描述符支持:
int:1
long:1
float:1
double:1
string:text
null
[Overwrite("Compute")]
private static int Compute(int value) => value * 3;Overwrite 完全替换目标方法。它的兼容风险和冲突风险最高,应只用于无法通过较小注入完成的修改。
[Intrinsic] 必须与 [Overwrite] 或 [Shadow] 一起使用。当前运行时在目标实现存在时保留目标实现并跳过 Intrinsic Overwrite,同时输出警告。
[Mixin(typeof(Example.Target))]
internal sealed class TargetMixin
{
[Shadow("_value")]
private int Value;
[Shadow("_fixed"), Final]
private int Fixed;
[Shadow("Helper")]
private int Helper(int value) => throw new NotSupportedException();
[Unique]
private static int LocalHelper() => 2;
}-
[Shadow]绑定目标字段、属性或方法,并验证名称和签名。 -
Optional = true的 Shadow 缺失时只记录警告。 -
[Final]要求目标字段为 readonly/const,或目标属性没有 setter。 -
[Mutable]或Shadow.Mutable = true允许写入原本 Final 的目标成员。 -
[Unique]声明 Mixin 自有成员。若目标存在同名成员,运行时记录隔离警告,不把它当作 Shadow。
Accessor 接口可以访问非公开字段、属性、方法和构造函数:
[Mixin(typeof(Example.Target))]
public interface TargetAccessor
{
[Accessor("_value")]
int Value { get; set; }
[Invoker("Multiply")]
int InvokeMultiply(int multiplier);
}
var accessor = MixinAccessors.Create<TargetAccessor>(targetInstance);
var value = accessor.Value;构造函数 Invoker:
[Mixin(typeof(Example.Target))]
public interface TargetFactory
{
[Invoker(".ctor")]
Example.Target Create(int value);
}
var factory = MixinAccessors.Create<TargetFactory>();写入 readonly 字段的 Accessor 必须声明 [Mutable]。Accessor 必须是带 [Mixin] 的接口;当前不支持泛型接口方法。
命名 Slice:
[Slice("middle", From = "int:2", To = "int:3")]
[Inject("Run", At = MixinAt.Invoke, Target = TargetCall,
Slice = "middle", Ordinal = 0, Shift = AtShift.After)]
private static void AfterCall()
{
}也可以直接写 SliceFrom 和 SliceTo。Ordinal 在 Slice 过滤完成后选择第几个匹配,索引从 0 开始。
AtShift:
-
Before:目标指令之前。 -
After:目标指令之后。 -
By:以目标指令为基准移动By条 IL 指令。
过度依赖 By 对编译器生成 IL 的变化非常敏感,应配合 Require、Expect 和测试使用。
public sealed class ExampleConfigPlugin : IMixinConfigPlugin
{
public bool ShouldApplyMixin(string targetTypeName, string mixinTypeName)
=> !mixinTypeName.EndsWith("DisabledMixin", StringComparison.Ordinal);
public void PreApply(MixinApplyContext context)
{
}
public void PostApply(MixinApplyContext context)
{
}
}MixinApplyContext 包含配置名、源程序集、Mixin 类型和目标类型。该接口用于 Mixin 筛选与应用校验。
优先级解析顺序为:
- 处理器上的
[Priority]。 - 操作 Attribute 的
Priority。 - Mixin 类型上的
[Priority]。 -
[Mixin(Priority = ...)]。 - Mixin 配置的
priority。
数值越高越先应用;相同优先级按发现顺序稳定排序。多个 Mixin 修改同一目标方法时,日志会输出每个插件、Mixin、操作、注入点、目标描述符和最终应用顺序。
公开诊断记录包括 MixinApplyResult、MixinPatchInfo、MixinConflictInfo 和 MixinApplyException。运行时对象本身由 Core 管理,插件不负责调用应用或回滚 API。