diff --git a/src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs b/src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs index 5b518209..80a8d74c 100644 --- a/src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs +++ b/src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs @@ -569,12 +569,14 @@ void EmitMethodBody() { if (parameters[i].IsByRef) { + Type byrefToType = parameters[i].GetElementType(); + ilGen.EmitLoadArg(i + 1); ilGen.Emit(OpCodes.Ldloc, argsLocal); ilGen.EmitInt(i); ilGen.Emit(OpCodes.Ldelem_Ref); ilGen.EmitConvertFromObject(parameters[i].GetElementType()); - ilGen.EmitStRef(parameters[i]); + ilGen.EmitStRef(byrefToType); } } if (!method.IsVoid()) @@ -622,12 +624,14 @@ void EmitProxyMethodBody() { if (parameterTypes[i].IsByRef) { + Type byrefToType = parameterTypes[i].GetElementType(); + ilGen.EmitLoadArg(i + 1); ilGen.Emit(OpCodes.Ldloc, parameters); ilGen.EmitInt(i); ilGen.Emit(OpCodes.Ldelem_Ref); - ilGen.EmitConvertFromObject(parameterTypes[i].GetElementType()); - ilGen.EmitStRef(parameterTypes[i]); + ilGen.EmitConvertFromObject(byrefToType); + ilGen.EmitStRef(byrefToType); } } } @@ -928,7 +932,7 @@ private static void CopyDefaultValueConstant(ParameterInfo from, ParameterBuilde // If this bug is present, it is caused by a `null` default value: defaultValue = null; } - catch (FormatException) when (from.ParameterType.GetTypeInfo().IsEnum) + catch (FormatException) when (from.ParameterType.IsEnum) { // This catch clause guards against a CLR bug that makes it impossible to query // the default value of a (closed generic) enum parameter. For the CoreCLR, see @@ -973,7 +977,7 @@ private static void CopyDefaultValueConstant(ParameterInfo from, ParameterBuilde // would "produce" a default value of `Missing.Value` in this situation). return; } - else if (parameterType.GetTypeInfo().IsValueType) + else if (parameterType.IsValueType) { // This guards against a CLR bug that prohibits replicating `null` default // values for non-nullable value types (which, despite the apparent type @@ -989,7 +993,7 @@ private static void CopyDefaultValueConstant(ParameterInfo from, ParameterBuilde else if (isNullableType) { parameterNonNullableType = from.ParameterType.GetGenericArguments()[0]; - if (parameterNonNullableType.GetTypeInfo().IsEnum || parameterNonNullableType.IsInstanceOfType(defaultValue)) + if (parameterNonNullableType.IsEnum || parameterNonNullableType.IsInstanceOfType(defaultValue)) { // This guards against two bugs: // diff --git a/src/AspectCore.Extensions.Reflection/Emit/ILGeneratorExtensions.cs b/src/AspectCore.Extensions.Reflection/Emit/ILGeneratorExtensions.cs index a8171c14..89f65472 100644 --- a/src/AspectCore.Extensions.Reflection/Emit/ILGeneratorExtensions.cs +++ b/src/AspectCore.Extensions.Reflection/Emit/ILGeneratorExtensions.cs @@ -210,25 +210,17 @@ public static void EmitCastToType(this ILGenerator ilGenerator, TypeInfo typeFro { throw new ArgumentNullException(nameof(ilGenerator)); } - if (!typeFrom.IsValueType && typeTo.IsValueType) + if (typeFrom.IsValueType) { - ilGenerator.Emit(OpCodes.Unbox_Any, typeTo.AsType()); - } - else if (typeFrom.IsValueType && !typeTo.IsValueType) - { - ilGenerator.Emit(OpCodes.Box, typeFrom.AsType()); - if (typeTo.AsType() != typeof(object)) + ilGenerator.Emit(OpCodes.Box, typeFrom); + if (typeTo != typeof(object)) { - ilGenerator.Emit(OpCodes.Castclass, typeTo.AsType()); + ilGenerator.Emit(OpCodes.Castclass, typeTo); } } - else if (!typeFrom.IsValueType && !typeTo.IsValueType) - { - ilGenerator.Emit(OpCodes.Castclass, typeTo.AsType()); - } else { - throw new InvalidCastException($"Caanot cast {typeFrom} to {typeTo}."); + ilGenerator.Emit(typeTo.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, typeTo); } } @@ -693,49 +685,48 @@ public static void EmitLdRef(this ILGenerator ilGenerator, Type type) { throw new ArgumentNullException(nameof(type)); } - if (type == typeof(short)) - { - ilGenerator.Emit(OpCodes.Ldind_I1); - } - else if (type == typeof(Int16)) - { - ilGenerator.Emit(OpCodes.Ldind_I2); - } - else if (type == typeof(Int32)) - { - ilGenerator.Emit(OpCodes.Ldind_I4); - } - else if (type == typeof(Int64)) - { - ilGenerator.Emit(OpCodes.Ldind_I8); - } - else if (type == typeof(float)) - { - ilGenerator.Emit(OpCodes.Ldind_R4); - } - else if (type == typeof(double)) - { - ilGenerator.Emit(OpCodes.Ldind_R8); - } - else if (type == typeof(ushort)) - { - ilGenerator.Emit(OpCodes.Ldind_U1); - } - else if (type == typeof(UInt16)) - { - ilGenerator.Emit(OpCodes.Ldind_U2); - } - else if (type == typeof(UInt32)) - { - ilGenerator.Emit(OpCodes.Ldind_U4); - } - else if (type.GetTypeInfo().IsValueType) - { - ilGenerator.Emit(OpCodes.Ldobj); - } - else + switch (Type.GetTypeCode(type)) { - ilGenerator.Emit(OpCodes.Ldind_Ref); + case TypeCode.SByte: + ilGenerator.Emit(OpCodes.Ldind_I1); + break; + case TypeCode.Boolean: + case TypeCode.Byte: + ilGenerator.Emit(OpCodes.Ldind_U1); + break; + case TypeCode.Int16: + ilGenerator.Emit(OpCodes.Ldind_I2); + break; + case TypeCode.Char: + case TypeCode.UInt16: + ilGenerator.Emit(OpCodes.Ldind_U2); + break; + case TypeCode.Int32: + ilGenerator.Emit(OpCodes.Ldind_I4); + break; + case TypeCode.UInt32: + ilGenerator.Emit(OpCodes.Ldind_U4); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + ilGenerator.Emit(OpCodes.Ldind_I8); + break; + case TypeCode.Single: + ilGenerator.Emit(OpCodes.Ldind_R4); + break; + case TypeCode.Double: + ilGenerator.Emit(OpCodes.Ldind_R8); + break; + default: + if (type.IsValueType) + { + ilGenerator.Emit(OpCodes.Ldobj, type); + } + else + { + ilGenerator.Emit(OpCodes.Ldind_Ref); + } + break; } } @@ -749,37 +740,42 @@ public static void EmitStRef(this ILGenerator ilGenerator, Type type) { throw new ArgumentNullException(nameof(type)); } - if (type == typeof(short)) - { - ilGenerator.Emit(OpCodes.Stind_I1); - } - else if (type == typeof(Int16)) - { - ilGenerator.Emit(OpCodes.Stind_I2); - } - else if (type == typeof(Int32)) - { - ilGenerator.Emit(OpCodes.Stind_I4); - } - else if (type == typeof(Int64)) - { - ilGenerator.Emit(OpCodes.Stind_I8); - } - else if (type == typeof(float)) - { - ilGenerator.Emit(OpCodes.Stind_R4); - } - else if (type == typeof(double)) - { - ilGenerator.Emit(OpCodes.Stind_R8); - } - else if (type.GetTypeInfo().IsValueType) - { - ilGenerator.Emit(OpCodes.Stobj); - } - else + switch (Type.GetTypeCode(type)) { - ilGenerator.Emit(OpCodes.Stind_Ref); + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.SByte: + ilGenerator.Emit(OpCodes.Stind_I1); + break; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + ilGenerator.Emit(OpCodes.Stind_I2); + break; + case TypeCode.Int32: + case TypeCode.UInt32: + ilGenerator.Emit(OpCodes.Stind_I4); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + ilGenerator.Emit(OpCodes.Stind_I8); + break; + case TypeCode.Single: + ilGenerator.Emit(OpCodes.Stind_R4); + break; + case TypeCode.Double: + ilGenerator.Emit(OpCodes.Stind_R8); + break; + default: + if (type.IsValueType) + { + ilGenerator.Emit(OpCodes.Stobj, type); + } + else + { + ilGenerator.Emit(OpCodes.Stind_Ref); + } + break; } } diff --git a/tests/AspectCore.Extensions.Autofac.Test/AspectCore.Extensions.Autofac.Test.csproj b/tests/AspectCore.Extensions.Autofac.Test/AspectCore.Extensions.Autofac.Test.csproj index 44e8eb14..9061bea9 100644 --- a/tests/AspectCore.Extensions.Autofac.Test/AspectCore.Extensions.Autofac.Test.csproj +++ b/tests/AspectCore.Extensions.Autofac.Test/AspectCore.Extensions.Autofac.Test.csproj @@ -27,8 +27,6 @@ - - diff --git a/tests/AspectCore.Extensions.Autofac.Test/Fakes/FakeServiceWithOut.cs b/tests/AspectCore.Extensions.Autofac.Test/Fakes/FakeServiceWithOut.cs new file mode 100644 index 00000000..6e73beac --- /dev/null +++ b/tests/AspectCore.Extensions.Autofac.Test/Fakes/FakeServiceWithOut.cs @@ -0,0 +1,37 @@ +using System.Globalization; +using System.Threading.Tasks; +using AspectCore.DynamicProxy; + +namespace AspectCore.Extensions.Test.Fakes +{ + public class FakeServiceWithOutInterceptor : AbstractInterceptorAttribute + { + public override async Task Invoke(AspectContext context, AspectDelegate next) + { + await next(context); + } + } + + [FakeServiceWithOutInterceptor] + public interface IFakeServiceWithOut + { + bool OutDecimal(out decimal num); + + bool OutInt(out int num); + } + + public class FakeServiceWithOut : IFakeServiceWithOut + { + public bool OutDecimal(out decimal num) + { + num = 1.0M; + return true; + } + + public bool OutInt(out int num) + { + num = 1; + return true; + } + } +} \ No newline at end of file diff --git a/tests/AspectCore.Extensions.Autofac.Test/RegistrationExtensionsTests.cs b/tests/AspectCore.Extensions.Autofac.Test/RegistrationExtensionsTests.cs index f93c4429..63ca8c50 100644 --- a/tests/AspectCore.Extensions.Autofac.Test/RegistrationExtensionsTests.cs +++ b/tests/AspectCore.Extensions.Autofac.Test/RegistrationExtensionsTests.cs @@ -1,5 +1,6 @@ using System.Reflection; using AspectCore.Configuration; +using AspectCore.DependencyInjection; using AspectCore.DynamicProxy; using AspectCore.Extensions.Autofac; using AspectCore.Extensions.Test.Fakes; @@ -67,5 +68,31 @@ public void AsProxyWithParamter_Test() var proxyController = container.Resolve(); Assert.Equal(proxyService.Get(100), proxyController.Execute()); } + + [Fact] + public void Intercept_OutWithDecimalParamter_Test() + { + var builder = CreateBuilder(); + builder.RegisterType().As(); + var container = builder.Build(); + + var proxyServiceWithOut = container.Resolve(); + decimal num; + Assert.True(proxyServiceWithOut.OutDecimal(out num)); + Assert.Equal(1.0M, num); + } + + [Fact] + public void Intercept_OutWithIntParamter_Test() + { + var builder = CreateBuilder(); + builder.RegisterType().As(); + var container = builder.Build(); + + var proxyServiceWithOut = container.Resolve(); + int num; + Assert.True(proxyServiceWithOut.OutInt(out num)); + Assert.Equal(1, num); + } } } diff --git a/tests/AspectCore.Tests/Classes.cs b/tests/AspectCore.Tests/Classes.cs index 8bfdea8e..98764726 100644 --- a/tests/AspectCore.Tests/Classes.cs +++ b/tests/AspectCore.Tests/Classes.cs @@ -243,4 +243,35 @@ string IFakeExplicitImplementation.GetVal_NonAspect() return "lemon"; } } + + public class FakeServiceWithOutInterceptor : AbstractInterceptorAttribute + { + public override async Task Invoke(AspectContext context, AspectDelegate next) + { + await next(context); + } + } + + [FakeServiceWithOutInterceptor] + public interface IFakeServiceWithOut + { + bool OutDecimal(out decimal num); + + bool OutInt(out int num); + } + + public class FakeServiceWithOut : IFakeServiceWithOut + { + public bool OutDecimal(out decimal num) + { + num = 1.0M; + return true; + } + + public bool OutInt(out int num) + { + num = 1; + return true; + } + } } \ No newline at end of file diff --git a/tests/AspectCore.Tests/DynamicProxy/AsyncAspectTests.cs b/tests/AspectCore.Tests/DynamicProxy/AsyncAspectTests.cs index 3ad6a8b6..85a2641a 100644 --- a/tests/AspectCore.Tests/DynamicProxy/AsyncAspectTests.cs +++ b/tests/AspectCore.Tests/DynamicProxy/AsyncAspectTests.cs @@ -4,6 +4,7 @@ using System.Text; using Xunit; using System.Threading.Tasks; +using AspectCore.DependencyInjection; namespace AspectCore.Tests.DynamicProxy { diff --git a/tests/AspectCore.Tests/Injector/GenericTest.cs b/tests/AspectCore.Tests/Injector/GenericTest.cs index 7bb93cb5..b30cdd68 100644 --- a/tests/AspectCore.Tests/Injector/GenericTest.cs +++ b/tests/AspectCore.Tests/Injector/GenericTest.cs @@ -32,11 +32,30 @@ public void Resolve_InstanceSimpleGeneric() Assert.IsType>(service); } + [Fact] + public void Intercept_OutWithDecimalParamter_Test() + { + var service = ServiceResolver.Resolve(); + decimal num; + Assert.True(service.OutDecimal(out num)); + Assert.Equal(1.0M, num); + } + + [Fact] + public void Intercept_OutWithIntParamter_Test() + { + var service = ServiceResolver.Resolve(); + int num; + Assert.True(service.OutInt(out num)); + Assert.Equal(1, num); + } + protected override void ConfigureService(IServiceContext services) { services.Transients.AddType(typeof(ISimpleGeneric<>), typeof(SimpleGeneric<>)); services.Transients.AddDelegate(typeof(IDelegateSimpleGeneric<>), r => new SimpleGeneric()); services.Singletons.AddInstance(typeof(IInstanceSimpleGeneric<>), new SimpleGeneric()); + services.Transients.AddType(); } } } \ No newline at end of file