inversionhourglass / Rougamo

Compile-time AOP component. Works with any method, whether it is async or sync, instance or static. Uses an aspectj-like pattern to match methods.
MIT License
393 stars 47 forks source link

方法参数使用ReadOnlySpan<byte>类型 运行时异常 #61

Closed abramped closed 7 months ago

abramped commented 7 months ago

[CusMoAttribute] public bool Test(ref T value, ushort packetId, ReadOnlySpan bytes) { return false } AOP成功后运行到此函数抛出异常 System.InvalidProgramException: Common Language Runtime detected an invalid program

其他使用函数参数带有ReadOnlySpan类型也会报错。

inversionhourglass commented 7 months ago

感谢反馈,将尽快修复

abramped commented 7 months ago

感谢反馈,将尽快修复

函数返回值是ref struct 也会出这个问题。

inversionhourglass commented 7 months ago

这个问题的原因是ref struct本身特性导致的,无法被装箱为object也无法从object拆箱获得,而Rougamo会将方法参数和返回值以object的形式保存到MethodContext中。

对于这种情况,目前的解决方案是不保存ref struct类型参数和返回值,不保存也就导致参数和返回值相关的一系列功能都将无法使用,包括记录参数值、修改参数值、刷新参数值、保存返回值、修改返回值、异常处理(然后修改返回值)。

由于ref struct影响众多功能,所以Rougamo将不默认对ref struct进行特殊处理,而是需要开发者自己明确定义不需要参数或返回值相关功能。具体表现与操作如下:

  1. 默认情况下,如果方法参数或返回值类型为ref struct,那么将在编译时报错
  2. 此时开发者需要明确自己是否真的不需要使用参数或返回值的相关功能,然后通过Omit.ArgumentsOmit.ReturnValue忽略参数或返回值的相关功能(当然,也可以把ref struct的参数或返回值的类型换掉)

    // 方式1,在定义MoAttribute子类时直接设置Omit
    public class T1Attribute : MoAttribute
    {
        public override Omit MethodContextOmits => Omit.Arguments | Omit.ReturnValue;
    }
    
    // 方式2(推荐),在应用Attribute时设置Omit
    public class T2Attribute : MoAttribute
    {
        public new Omit MethodContextOmits { get; set; }
    }
    
    [T2(MethodContextOmits = Omit.Arguments)]
    public void ReadOnlySpanIn(ReadOnlySpan<char> span) { }
    
    [T2(MethodContextOmits = Omit.ReturnValue)]
    public ReadOnlySpan<char> ReadOnlySpanOut() => default;

现在已发布2.3.0预览版,可以更新试一下,预计周一前发布正式版,如果有这个问题的相关建议,也可以提出

inversionhourglass commented 7 months ago

2.3.0 正式版已发布