Skip to content

Mixin Reference

Ling edited this page Jul 22, 2026 · 1 revision

Mixin API 参考

PCL.Mixin 命名空间直接位于 PCL.Core.dll。插件项目引用目标启动器版本的 PCL.Core.dll 后即可使用下列公共类型。

Mixin 类型声明

[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 类,便于定位日志。

操作公共参数

InjectOverwriteRedirectModifyArgModifyArgsModifyVariableModifyConstant 都继承 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 与 CallbackInfo

[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 把指定方法调用、字段访问或其他受支持指令替换为处理器:

[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 与 ModifyArgs

修改一个调用参数:

[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 与 ModifyConstant

[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 与 Intrinsic

[Overwrite("Compute")]
private static int Compute(int value) => value * 3;

Overwrite 完全替换目标方法。它的兼容风险和冲突风险最高,应只用于无法通过较小注入完成的修改。

[Intrinsic] 必须与 [Overwrite][Shadow] 一起使用。当前运行时在目标实现存在时保留目标实现并跳过 Intrinsic Overwrite,同时输出警告。

Shadow、Final、Mutable 与 Unique

[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 与 Invoker

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、Ordinal 与 Shift

命名 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()
{
}

也可以直接写 SliceFromSliceToOrdinal 在 Slice 过滤完成后选择第几个匹配,索引从 0 开始。

AtShift

  • Before:目标指令之前。
  • After:目标指令之后。
  • By:以目标指令为基准移动 By 条 IL 指令。

过度依赖 By 对编译器生成 IL 的变化非常敏感,应配合 RequireExpect 和测试使用。

配置处理器

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 筛选与应用校验。

优先级与冲突

优先级解析顺序为:

  1. 处理器上的 [Priority]
  2. 操作 Attribute 的 Priority
  3. Mixin 类型上的 [Priority]
  4. [Mixin(Priority = ...)]
  5. Mixin 配置的 priority

数值越高越先应用;相同优先级按发现顺序稳定排序。多个 Mixin 修改同一目标方法时,日志会输出每个插件、Mixin、操作、注入点、目标描述符和最终应用顺序。

公开诊断记录包括 MixinApplyResultMixinPatchInfoMixinConflictInfoMixinApplyException。运行时对象本身由 Core 管理,插件不负责调用应用或回滚 API。

Clone this wiki locally