dotnetcore / AspectCore-Framework

AspectCore is an AOP-based cross platform framework for .NET Standard.
MIT License
1.68k stars 319 forks source link

2.3.0版本升级后,发生System.NullReferenceException异常 #305

Closed dxc272 closed 1 year ago

dxc272 commented 1 year ago

【ITestService.cs】

namespace WebApplication
{
    public interface ITestService
    {
        void Update((string a, string b, string c, string d, string e, string f, string g, string h) tupleKey);
    }
}

【TestService.cs】

namespace WebApplication
{
    public class TestService : ITestService
    {
        public void Update((string a, string b, string c, string d, string e, string f, string g, string h) tupleKey)
        {
        }
    }
}

【Program.cs】

namespace WebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddControllers();
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
            builder.Services.AddScoped<ITestService, TestService>();
            //↓mark1
            builder.Host.UseDynamicProxy();
            //↓mark2
            var app = builder.Build();
            app.MapControllers();
            app.Run();
        }
    }
}

.net6.0下,在该包升级到2.3.0版本后,当依赖注入的接口中的方法参数是元组,且元组的元素个数大于7个的时候,在上记代码块mark2处会报System.NullReferenceException异常。内部报错的地方是src/AspectCore.Extensions.Reflection/Emit/ILGeneratorExtensions.cs 的EmitArray方法内

在2.3.0之前的版本没有这个问题,当方法参数中元组的元素个数≤7时也没有这个问题。由于取元组第8个元素需要通过Rest属性嵌套取,因此感觉是2.3.0版本在取元组第8个元素时取不到值为null,在GetType()时发生该异常。

由于项目中目前正在使用该包并想升级到最新版,希望有时间的话可以得到确认,如果是2.3.0版本的问题的话希望得到修正。 不胜感激。

liuhaoyang commented 1 year ago

有兴趣可以自己尝试解决一下看看 ?对 EMIT 部分的代码如果有问题可以在issue上讨论

93910676wangd commented 1 year ago

有兴趣可以自己尝试解决一下看看 ?对 EMIT 部分的代码如果有问题可以在issue上讨论

升级会有问题哦,😮😮😮

MarsonShine commented 1 year ago

导致这个bug的原因是,当参数是具名tuple的时候就会导致这个问题,因为编译器会给tuple添加 TupleElementNamesAttribute 自定义属性。所以进而触发这段代码

namespace AspectCore.Extensions.Reflection
{
    public partial class ParameterReflector : ICustomAttributeReflectorProvider
    {
        ...
        private ParameterReflector(ParameterInfo reflectionInfo)
        {
            // 省略其它代码
            _customAttributeReflectors = _reflectionInfo.CustomAttributes.Select(data => CustomAttributeReflector.Create(data)).ToArray();
        }
        ...
    }
}

又因为当参数超过7个时,就会走嵌套 ValueTuple 的逻辑,所以 Update 方法编译器会生成如下代码:

public void Update([TupleElementNames(new string[] { "a", "b", "c", "d", "e", "f", "g", "h", null })] ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>> tupleKey)
{
}

那么修复的方式就有多种了: 不升级库的方式:不用具名的元组类型,也就是

void Update((string, string, string, string, string, string, string, string) tupleKey); //  超过7个参数

修改源码,将 ParameterReflector.cs 的代码的 CustomAttributes 过滤掉 TupleElementNamesAttribute 类型,或者判断参数类型位 tuple 时,不走这个逻辑。(ps:这个 _customAttributeReflectors 什么作用,我还没深入研究)

private ParameterReflector(ParameterInfo reflectionInfo)
 {
        // 省略其它代码
        if (!reflectionInfo.ParameterType.IsTupleType()) {
            _customAttributeReflectors = _reflectionInfo.CustomAttributes.Select(data => CustomAttributeReflector.Create(data)).ToArray();
        }
}
liuhaoyang commented 1 year ago

赞,要么试着修复一下