Skip to content

Commit bd11d18

Browse files
committed
fix test cases
1 parent 75bf605 commit bd11d18

File tree

6 files changed

+115
-39
lines changed

6 files changed

+115
-39
lines changed

src/AspectCore.Core/Extensions/EnumerableExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using System.Collections.Generic;
2-
using System.Linq;
32

43
// ReSharper disable once CheckNamespace
5-
namespace AspectCore.Extensions
4+
namespace System.Linq
65
{
76
internal static class EnumerableExtensions
87
{

src/AspectCore.Core/Extensions/MethodInfoExtensions.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Reflection;
45

@@ -7,6 +8,8 @@ namespace AspectCore.Extensions
78
{
89
internal static class MethodInfoExtensions
910
{
11+
public static readonly Type PreserveBaseOverridesAttribute = Type.GetType("System.Runtime.CompilerServices.PreserveBaseOverridesAttribute", false);
12+
1013
public static IEnumerable<MethodInfo> GetInterfaceDeclarations(this MethodInfo method)
1114
{
1215
var typeInfo = method.ReflectedType?.GetTypeInfo();
@@ -23,6 +26,35 @@ public static IEnumerable<MethodInfo> GetInterfaceDeclarations(this MethodInfo m
2326
}
2427
}
2528
}
29+
30+
public static bool IsOverriden(this MethodInfo method)
31+
{
32+
return method.GetBaseDefinition() != method;
33+
}
34+
35+
public static bool IsPreserveBaseOverride(this MethodInfo method, bool checkBase)
36+
{
37+
if (PreserveBaseOverridesAttribute is null)
38+
return false;
39+
40+
var m = method;
41+
while (true)
42+
{
43+
if (m.IsDefined(PreserveBaseOverridesAttribute))
44+
return true;
45+
46+
if (checkBase == false)
47+
break;
48+
49+
var b = m.GetBaseDefinition();
50+
if (b == m || b == null)
51+
break;
52+
53+
m = b;
54+
}
55+
56+
return false;
57+
}
2658
}
2759
}
2860

src/AspectCore.Core/Utils/ProxyGeneratorUtils.CovariantReturnMethod.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@ namespace AspectCore.Utils
1212
// For interface proxy: We need to use the covariant return methods as the interface methods' implementation.
1313
internal partial class ProxyGeneratorUtils
1414
{
15-
private static readonly Type PreserveBaseOverridesAttribute = Type.GetType("System.Runtime.CompilerServices.PreserveBaseOverridesAttribute", false);
16-
1715
// key: covariant return method
1816
// value: interface method declarations
1917
internal static IReadOnlyDictionary<MethodInfo, HashSet<MethodInfo>> GetCovariantReturnMethodMap(Type implType)
2018
{
2119
var result = new Dictionary<MethodInfo, HashSet<MethodInfo>>();
2220
// No PreserveBaseOverridesAttribute means that the runtime does not support covariant return types.
23-
if (PreserveBaseOverridesAttribute is null)
21+
if (AspectCore.Extensions.MethodInfoExtensions.PreserveBaseOverridesAttribute is null)
2422
return result;
2523

24+
25+
var methods = implType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
26+
.ToHashSet();
27+
2628
const MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot;
2729
var covariantReturnMethods = implType
2830
.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
29-
.Where(m => (m.Attributes & attributes) == attributes)
30-
.Where(m => m.IsDefined(PreserveBaseOverridesAttribute))
31+
.Where(m => m.IsPreserveBaseOverride(true))
3132
.ToHashSet();
3233

3334
foreach (var method in covariantReturnMethods)

src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading;
1010
using System.Threading.Tasks;
1111
using AspectCore.DynamicProxy;
12+
using AspectCore.Extensions;
1213
using AspectCore.Extensions.Reflection;
1314
using AspectCore.Extensions.Reflection.Emit;
1415

@@ -457,34 +458,12 @@ internal static MethodBuilder DefineClassMethod(MethodInfo method, Type implType
457458
attributes |= MethodAttributes.FamORAssem;
458459
}
459460

460-
// NewSlot is required for covariant return types.
461-
if (method.IsDefined(PreserveBaseOverridesAttribute) && method.Attributes.HasFlag(MethodAttributes.NewSlot))
462-
{
463-
attributes |= MethodAttributes.NewSlot;
464-
}
465-
466461
var methodBuilder = DefineMethod(method, method.Name, attributes, implType, typeDesc);
467462
return methodBuilder;
468463
}
469464

470465
private static MethodBuilder DefineMethod(MethodInfo method, string name, MethodAttributes attributes, Type implType, TypeDesc typeDesc, MethodInfo covariantReturnMethod = null)
471466
{
472-
var methodBuilder = typeDesc.Builder.DefineMethod(name, attributes, method.CallingConvention, method.ReturnType, method.GetParameterTypes());
473-
474-
GenericParameterUtils.DefineGenericParameter(method, methodBuilder);
475-
476-
//define method attributes
477-
methodBuilder.SetCustomAttribute(CustomAttributeBuilderUtils.DefineCustomAttribute(typeof(DynamicallyAttribute)));
478-
479-
//inherit targetMethod's attribute
480-
foreach (var customAttributeData in method.CustomAttributes)
481-
{
482-
methodBuilder.SetCustomAttribute(CustomAttributeBuilderUtils.DefineCustomAttribute(customAttributeData));
483-
}
484-
485-
//define parameters
486-
ParameterBuilderUtils.DefineParameters(method, methodBuilder);
487-
488467
var implementationMethod = covariantReturnMethod ?? implType.GetTypeInfo().GetMethodBySignature(method);
489468
if (implementationMethod == null)
490469
{
@@ -516,6 +495,34 @@ private static MethodBuilder DefineMethod(MethodInfo method, string name, Method
516495
}
517496
}
518497

498+
// NOTE: both covariant return method and its corresponding overridden method should be defined with NewSlot attribute.
499+
if (method.IsPreserveBaseOverride(true))
500+
{
501+
// PreserveBaseOverridesAttribute is used to indicate that the method is a covariant return method.
502+
attributes |= MethodAttributes.NewSlot;
503+
}
504+
else if (implementationMethod.Attributes.HasFlag(MethodAttributes.NewSlot) && implementationMethod.IsOverriden())
505+
{
506+
// an overridden method with NewSlot attribute is a method overriden covariant return method.
507+
attributes |= MethodAttributes.NewSlot;
508+
}
509+
510+
var methodBuilder = typeDesc.Builder.DefineMethod(name, attributes, method.CallingConvention, method.ReturnType, method.GetParameterTypes());
511+
512+
GenericParameterUtils.DefineGenericParameter(method, methodBuilder);
513+
514+
//define method attributes
515+
methodBuilder.SetCustomAttribute(CustomAttributeBuilderUtils.DefineCustomAttribute(typeof(DynamicallyAttribute)));
516+
517+
//inherit targetMethod's attribute
518+
foreach (var customAttributeData in method.CustomAttributes)
519+
{
520+
methodBuilder.SetCustomAttribute(CustomAttributeBuilderUtils.DefineCustomAttribute(customAttributeData));
521+
}
522+
523+
//define parameters
524+
ParameterBuilderUtils.DefineParameters(method, methodBuilder);
525+
519526
if (method.IsNonAspect())
520527
{
521528
EmitMethodBody();

src/AspectCore.Extensions.Reflection/MethodSignature.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,19 @@ private static int GetSignatureCode(Pair<MethodBase, string> pair)
6363
if (parameterTypes.Length > 0)
6464
{
6565
signatureCode = (signatureCode * 397) ^ parameterTypes.Length.GetHashCode();
66-
foreach (var paramterType in parameterTypes)
66+
foreach (var parameterType in parameterTypes)
6767
{
68-
if (paramterType.IsGenericParameter)
68+
if (parameterType.IsGenericParameter)
6969
{
7070
continue;
7171
}
72-
else if (paramterType.GetTypeInfo().IsGenericType)
72+
else if (parameterType.GetTypeInfo().IsGenericType)
7373
{
74-
signatureCode = GetSignatureCode(signatureCode, paramterType);
74+
signatureCode = GetSignatureCode(signatureCode, parameterType);
7575
}
7676
else
7777
{
78-
signatureCode = (signatureCode * 397) ^ paramterType.GetHashCode();
78+
signatureCode = (signatureCode * 397) ^ parameterType.GetHashCode();
7979
}
8080
}
8181
}

tests/AspectCore.Tests/DynamicProxy/CovariantReturnMethodTests.cs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,68 @@ public class Service : IService
1919

2020
public class CovariantReturnsService : Service
2121
{
22-
public sealed override string Method() => nameof(CovariantReturnsService);
22+
public override string Method() => nameof(CovariantReturnsService);
2323
public override string Property { get; } = nameof(CovariantReturnsService);
2424
}
2525

26+
public class DerivedCovariantReturnsService : CovariantReturnsService
27+
{
28+
public override string Method() => nameof(DerivedCovariantReturnsService);
29+
}
30+
2631
[Fact]
27-
public void CreateClassProxy_CovariantReturns_Test()
32+
public void CreateClassProxy_CovariantReturnsService_Test()
2833
{
2934
var service = ProxyGenerator.CreateClassProxy<CovariantReturnsService>();
3035
Assert.Equal(nameof(CovariantReturnsService), service.Method());
3136
Assert.Equal(nameof(CovariantReturnsService), service.Property);
3237
}
3338

3439
[Fact]
35-
public void CreateClassProxy_WithServiceType_CovariantReturns_Test()
40+
public void CreateClassProxy_DerivedCovariantReturnsService_Test()
41+
{
42+
var service = ProxyGenerator.CreateClassProxy<DerivedCovariantReturnsService>();
43+
Assert.Equal(nameof(DerivedCovariantReturnsService), service.Method());
44+
Assert.Equal(nameof(CovariantReturnsService), service.Property);
45+
}
46+
47+
[Fact]
48+
public void CreateClassProxy_Service_CovariantReturnsService_Test()
3649
{
3750
var service = ProxyGenerator.CreateClassProxy<Service, CovariantReturnsService>();
3851
Assert.Equal(nameof(CovariantReturnsService), service.Method());
3952
Assert.Equal(nameof(CovariantReturnsService), service.Property);
4053
}
4154

4255
[Fact]
43-
public void CreateInterfaceProxy_CovariantReturns_Test()
56+
public void CreateClassProxy_Service_DerivedCovariantReturnsService_Test()
57+
{
58+
var service = ProxyGenerator.CreateClassProxy<Service, DerivedCovariantReturnsService>();
59+
Assert.Equal(nameof(DerivedCovariantReturnsService), service.Method());
60+
Assert.Equal(nameof(CovariantReturnsService), service.Property);
61+
}
62+
63+
[Fact]
64+
public void CreateClassProxy_CovariantReturnsService_DerivedCovariantReturnsService_Test()
65+
{
66+
var service = ProxyGenerator.CreateClassProxy<CovariantReturnsService, DerivedCovariantReturnsService>();
67+
Assert.Equal(nameof(DerivedCovariantReturnsService), service.Method());
68+
Assert.Equal(nameof(CovariantReturnsService), service.Property);
69+
}
70+
71+
[Fact]
72+
public void CreateInterfaceProxy_IService_CovariantReturnsService_Test()
4473
{
4574
var service = ProxyGenerator.CreateInterfaceProxy<IService, CovariantReturnsService>();
4675
Assert.Equal(nameof(CovariantReturnsService), service.Method());
4776
Assert.Equal(nameof(CovariantReturnsService), service.Property);
4877
}
78+
79+
[Fact]
80+
public void CreateInterfaceProxy_IService_DerivedCovariantReturnsService_Test()
81+
{
82+
var service = ProxyGenerator.CreateInterfaceProxy<IService, DerivedCovariantReturnsService>();
83+
Assert.Equal(nameof(DerivedCovariantReturnsService), service.Method());
84+
Assert.Equal(nameof(CovariantReturnsService), service.Property);
85+
}
4986
}

0 commit comments

Comments
 (0)