From eeceaf0231a689c486290f327587498055b3ad78 Mon Sep 17 00:00:00 2001 From: Jerry Bai Date: Mon, 15 Jun 2020 00:06:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=8D=E5=B0=84=E8=B0=83=E7=94=A8=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=A7=94=E6=89=98=E8=B0=83=E7=94=A8=EF=BC=9B=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E5=99=A8=E7=B1=BB=E5=9E=8B=E6=94=B9=E4=B8=BA=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E4=BC=A0=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dotnetcore.yml | 14 +- .gitignore | 4 +- Makefile | 34 +-- README.md | 24 +- .../Larva.DynamicProxy.nuspec | 29 -- package.png | Bin 0 -> 7534 bytes .../Application/IUserLoginService.cs | 11 - src/DynamicProxyTests/Application/UserDto.cs | 7 - .../Application/AnotherUserLoginService.cs | 11 +- .../Application/IUserLoginService.cs | 15 ++ .../Application/UserDto.cs | 12 + .../Application/UserLoginService.cs | 15 +- .../DynamicProxyFactoryTest.cs | 54 ++-- .../PerformanceCounterInterceptor.cs | 16 +- .../UserLoginCounterInterceptor.cs | 10 +- .../Larva.DynamicProxy.Tests.csproj} | 6 +- .../Repositories/IUserLoginRepository.cs | 4 +- .../Repositories/UserLoginRepository.cs | 9 +- src/Larva.DynamicProxy.sln | 50 +++- src/Larva.DynamicProxy/DefaultInvocation.cs | 88 ------ src/Larva.DynamicProxy/DynamicProxyFactory.cs | 57 ++-- src/Larva.DynamicProxy/Emitters/Consts.cs | 4 +- .../Emitters/EmitterHelper.cs | 13 - .../Emitters/IMemberEmitter.cs | 7 + .../Emitters/IProxyTypeGeneratorInfo.cs | 23 +- .../Emitters/ProxyConstructorEmitter.cs | 11 + .../Emitters/ProxyEventEmitter.cs | 13 +- .../Emitters/ProxyMethodEmitter.cs | 249 ++++++++++++----- .../Emitters/ProxyPropertyEmitter.cs | 254 ++++++++++-------- .../Emitters/ProxyTypeGenerateWay.cs | 9 + .../Emitters/ProxyTypeGenerator.cs | 63 +++-- src/Larva.DynamicProxy/IInterceptor.cs | 7 + src/Larva.DynamicProxy/IInvocation.cs | 46 +++- .../InvalidProxiedInterfaceTypeException.cs | 19 +- .../InvalidProxiedTypeException.cs | 19 +- src/Larva.DynamicProxy/InvocationBase.cs | 109 ++++++++ .../Larva.DynamicProxy.csproj | 35 ++- src/Larva.DynamicProxy/MemberOperateTypes.cs | 12 + src/Larva.DynamicProxy/MethodInvocation.cs | 49 ++++ .../PropertyGetInvocation.cs | 47 ++++ .../PropertySetInvocation.cs | 49 ++++ src/Larva.DynamicProxy/StandardInterceptor.cs | 94 ++++++- src/Larva.DynamicProxy/WrapperObject.cs | 21 -- 43 files changed, 1097 insertions(+), 526 deletions(-) delete mode 100644 nuget/Larva.DynamicProxy/Larva.DynamicProxy.nuspec create mode 100644 package.png delete mode 100644 src/DynamicProxyTests/Application/IUserLoginService.cs delete mode 100644 src/DynamicProxyTests/Application/UserDto.cs rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Application/AnotherUserLoginService.cs (54%) create mode 100644 src/Larva.DynamicProxy.Tests/Application/IUserLoginService.cs create mode 100644 src/Larva.DynamicProxy.Tests/Application/UserDto.cs rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Application/UserLoginService.cs (61%) rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/DynamicProxyFactoryTest.cs (57%) rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Interceptors/PerformanceCounterInterceptor.cs (54%) rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Interceptors/UserLoginCounterInterceptor.cs (77%) rename src/{DynamicProxyTests/DynamicProxyTests.csproj => Larva.DynamicProxy.Tests/Larva.DynamicProxy.Tests.csproj} (75%) rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Repositories/IUserLoginRepository.cs (57%) rename src/{DynamicProxyTests => Larva.DynamicProxy.Tests}/Repositories/UserLoginRepository.cs (53%) delete mode 100644 src/Larva.DynamicProxy/DefaultInvocation.cs delete mode 100644 src/Larva.DynamicProxy/Emitters/EmitterHelper.cs create mode 100644 src/Larva.DynamicProxy/InvocationBase.cs create mode 100644 src/Larva.DynamicProxy/MethodInvocation.cs create mode 100644 src/Larva.DynamicProxy/PropertyGetInvocation.cs create mode 100644 src/Larva.DynamicProxy/PropertySetInvocation.cs delete mode 100644 src/Larva.DynamicProxy/WrapperObject.cs diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index b0df045..1ddd4b6 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -1,6 +1,10 @@ name: .NET Core -on: [push] +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] jobs: build: @@ -8,12 +12,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 2.2.108 + dotnet-version: 3.1.101 + - name: build + run: make build - name: test run: make test - - name: build - run: make rebuild diff --git a/.gitignore b/.gitignore index 670092c..5f52eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -330,5 +330,5 @@ ASALocalRun/ .mfractor/ # Custom -nuget/*/lib/ -.vscode/ +.DS_Store +.vscode diff --git a/Makefile b/Makefile index 2ee62d9..d02e6ed 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,12 @@ all: test pack test: - dotnet test `pwd`/src/DynamicProxyTests/ + dotnet test `pwd`/src/Larva.DynamicProxy.Tests/ -pack: rebuild - rm -rf `pwd`/nuget/.DS_Store - rm -rf `pwd`/nuget/*/.DS_Store - rm -rf `pwd`/nuget/*/*/.DS_Store - rm -rf `pwd`/nuget/*/lib/*/*.pdb - rm -rf `pwd`/nuget/*/lib/*/*.json - nuget pack -OutputDirectory `pwd`/packages/ `pwd`/nuget/Larva.DynamicProxy/Larva.DynamicProxy.nuspec +pack: build + mkdir -p `pwd`/packages + dotnet pack -c Release `pwd`/src/Larva.DynamicProxy/ + mv `pwd`/src/Larva.DynamicProxy/bin/Release/*.nupkg `pwd`/packages/ -rebuild: clean build - -clean: - rm -rf `pwd`/nuget/.DS_Store - rm -rf `pwd`/nuget/*/.DS_Store - rm -rf `pwd`/nuget/*/*/.DS_Store - rm -rf `pwd`/nuget/*/lib/* - -build: build-1_6 build-2_0 build-netFramework - -build-1_6: - dotnet build -c Release -f 'netstandard1.6' -o `pwd`/nuget/Larva.DynamicProxy/lib/netstandard1.6/ `pwd`/src/Larva.DynamicProxy/ - -build-2_0: - dotnet build -c Release -f 'netstandard2.0' -o `pwd`/nuget/Larva.DynamicProxy/lib/netstandard2.0/ `pwd`/src/Larva.DynamicProxy/ - -build-netFramework: - msbuild `pwd`/src/Larva.DynamicProxy/Larva.DynamicProxy.csproj -r -noConLog -t:Rebuild -p:Configuration=Release -p:TargetFramework=net45 -p:OutputPath=`pwd`/nuget/Larva.DynamicProxy/lib/net45/ +build: + dotnet build -c Release `pwd`/src/Larva.DynamicProxy/ + dotnet build -c Release `pwd`/src/Larva.DynamicProxy.Tests/ diff --git a/README.md b/README.md index fa1126c..b5321dd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Larva.DynamicProxy + dotnet 动态代理类,用于AOP。可以结合IoC框架。此动态代理仅支持通过实现接口来创建代理类。 - 基于对象,返回指定接口的代理类对象,此代理类引用原始对象; @@ -9,28 +10,25 @@ dotnet 动态代理类,用于AOP。可以结合IoC框架。此动态代理仅 - StandardInterceptor 支持拦截Task异步方法。 -## 兼容性 - -- netstandard 1.6 - -- netstandard 2.0 - -- dotNetFramework 4.5 及以上 - -## 安装Nuget包 +## 安装 -``` -Install-Package Larva.DynamicProxy -或 +```sh dotnet add package Larva.DynamicProxy ``` ## 调用示例 -示例参见:[DynamicProxyTests](https://github.com/freshncp/Larva.DynamicProxy/tree/master/src/DynamicProxyTests) +示例参见:[Larva.DynamicProxy.Tests](src/Larva.DynamicProxy.Tests) ## 更新历史 +### 2.0.0-beta1 (更新日期:2020/06/14) + +```plain +1)重构,取消反射调用,改为委托调用; +2)拦截器,由类型改为对象传入。 +``` + ### 1.0.7 (更新日期:2019/12/17) ```plain diff --git a/nuget/Larva.DynamicProxy/Larva.DynamicProxy.nuspec b/nuget/Larva.DynamicProxy/Larva.DynamicProxy.nuspec deleted file mode 100644 index 24b6a72..0000000 --- a/nuget/Larva.DynamicProxy/Larva.DynamicProxy.nuspec +++ /dev/null @@ -1,29 +0,0 @@ - - - - Larva.DynamicProxy - 1.0.7 - Larva.DynamicProxy - Jerry Bai (QQ:407547953) - Jerry Bai (QQ:407547953) - true - MIT - https://github.com/freshncp/Larva.DynamicProxy - dotnet 动态代理类,用于AOP - dotnet 动态代理类,用于AOP - - freshncp - zh-Hans - dynamic proxy aop ioc - - - - - - - - - - - - \ No newline at end of file diff --git a/package.png b/package.png new file mode 100644 index 0000000000000000000000000000000000000000..3d62953157fc10434aaa9289df916d7a83fc8323 GIT binary patch literal 7534 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 literal 0 HcmV?d00001 diff --git a/src/DynamicProxyTests/Application/IUserLoginService.cs b/src/DynamicProxyTests/Application/IUserLoginService.cs deleted file mode 100644 index d0dabcd..0000000 --- a/src/DynamicProxyTests/Application/IUserLoginService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; - -namespace DynamicProxyTests.Application -{ - public interface IUserLoginService - { - bool Login(string userName, string password, out bool accountExists, ref int retryCount, out UserDto userDto); - - Task LoginAsync(string userName, string password); - } -} diff --git a/src/DynamicProxyTests/Application/UserDto.cs b/src/DynamicProxyTests/Application/UserDto.cs deleted file mode 100644 index d857734..0000000 --- a/src/DynamicProxyTests/Application/UserDto.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DynamicProxyTests.Application -{ - public class UserDto - { - public string RealName { get;set; } - } -} \ No newline at end of file diff --git a/src/DynamicProxyTests/Application/AnotherUserLoginService.cs b/src/Larva.DynamicProxy.Tests/Application/AnotherUserLoginService.cs similarity index 54% rename from src/DynamicProxyTests/Application/AnotherUserLoginService.cs rename to src/Larva.DynamicProxy.Tests/Application/AnotherUserLoginService.cs index b377630..dc09348 100644 --- a/src/DynamicProxyTests/Application/AnotherUserLoginService.cs +++ b/src/Larva.DynamicProxy.Tests/Application/AnotherUserLoginService.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace DynamicProxyTests.Application +namespace Larva.DynamicProxy.Tests.Application { public class AnotherUserLoginService : IUserLoginService @@ -9,8 +9,10 @@ private AnotherUserLoginService() { } - public bool Login(string userName, string password, out bool accountExists, ref int retryCount, out UserDto userDto) + public bool Login(string userName, string password, int sault, out bool accountExists, ref int retryCount, out UserDto userDto) { + UserName = userName; + Sault = sault; accountExists = true; ++retryCount; userDto = null; @@ -19,7 +21,12 @@ public bool Login(string userName, string password, out bool accountExists, ref public Task LoginAsync(string userName, string password) { + UserName = userName; return Task.FromResult(false); } + + public string UserName { get; private set;} + + public int Sault { get; set; } } } diff --git a/src/Larva.DynamicProxy.Tests/Application/IUserLoginService.cs b/src/Larva.DynamicProxy.Tests/Application/IUserLoginService.cs new file mode 100644 index 0000000..a260c80 --- /dev/null +++ b/src/Larva.DynamicProxy.Tests/Application/IUserLoginService.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace Larva.DynamicProxy.Tests.Application +{ + public interface IUserLoginService + { + bool Login(string userName, string password, int sault, out bool accountExists, ref int retryCount, out UserDto userDto); + + Task LoginAsync(string userName, string password); + + string UserName { get; } + + int Sault { get; set; } + } +} diff --git a/src/Larva.DynamicProxy.Tests/Application/UserDto.cs b/src/Larva.DynamicProxy.Tests/Application/UserDto.cs new file mode 100644 index 0000000..86aad7c --- /dev/null +++ b/src/Larva.DynamicProxy.Tests/Application/UserDto.cs @@ -0,0 +1,12 @@ +namespace Larva.DynamicProxy.Tests.Application +{ + public class UserDto + { + public string RealName { get; set; } + + public override string ToString() + { + return $"UserDto:RealName={RealName}"; + } + } +} \ No newline at end of file diff --git a/src/DynamicProxyTests/Application/UserLoginService.cs b/src/Larva.DynamicProxy.Tests/Application/UserLoginService.cs similarity index 61% rename from src/DynamicProxyTests/Application/UserLoginService.cs rename to src/Larva.DynamicProxy.Tests/Application/UserLoginService.cs index b56ae02..d02a65e 100644 --- a/src/DynamicProxyTests/Application/UserLoginService.cs +++ b/src/Larva.DynamicProxy.Tests/Application/UserLoginService.cs @@ -1,7 +1,7 @@ -using DynamicProxyTests.Repositories; +using Larva.DynamicProxy.Tests.Repositories; using System.Threading.Tasks; -namespace DynamicProxyTests.Application +namespace Larva.DynamicProxy.Tests.Application { public class UserLoginService : IUserLoginService { @@ -12,17 +12,24 @@ public UserLoginService(IUserLoginRepository userLoginRepository) _userLoginRepository = userLoginRepository; } - public bool Login(string userName, string password, out bool accountExists, ref int retryCount, out UserDto userDto) + public bool Login(string userName, string password, int sault, out bool accountExists, ref int retryCount, out UserDto userDto) { + UserName = userName; + Sault = sault; accountExists = true; ++retryCount; userDto = new UserDto { RealName = userName }; - return _userLoginRepository.Validate(userName, password); + return _userLoginRepository.Validate(userName, password, sault); } public async Task LoginAsync(string userName, string password) { + UserName = userName; return await _userLoginRepository.ValidateAsync(userName, password); } + + public string UserName { get; private set;} + + public int Sault { get; set; } } } diff --git a/src/DynamicProxyTests/DynamicProxyFactoryTest.cs b/src/Larva.DynamicProxy.Tests/DynamicProxyFactoryTest.cs similarity index 57% rename from src/DynamicProxyTests/DynamicProxyFactoryTest.cs rename to src/Larva.DynamicProxy.Tests/DynamicProxyFactoryTest.cs index 7adf40d..9cab414 100644 --- a/src/DynamicProxyTests/DynamicProxyFactoryTest.cs +++ b/src/Larva.DynamicProxy.Tests/DynamicProxyFactoryTest.cs @@ -1,10 +1,10 @@ using System; -using DynamicProxyTests.Application; -using DynamicProxyTests.Interceptors; -using DynamicProxyTests.Repositories; +using Larva.DynamicProxy.Tests.Application; +using Larva.DynamicProxy.Tests.Interceptors; +using Larva.DynamicProxy.Tests.Repositories; using Xunit; -namespace DynamicProxyTests +namespace Larva.DynamicProxy.Tests { public class DynamicProxyFactoryTest { @@ -13,15 +13,24 @@ public void TestCreateProxyT() { var userLoginService = Larva.DynamicProxy.DynamicProxyFactory.CreateProxy( new UserLoginService(new UserLoginRepository()), - new Type[] { - typeof(UserLoginCounterInterceptor), - typeof(PerformanceCounterInterceptor) + new IInterceptor[] { + new UserLoginCounterInterceptor(), + new PerformanceCounterInterceptor() }); Assert.Equal($"{typeof(UserLoginService).Name}__DynamicProxyByInstance", userLoginService.GetType().Name); + int retryCount = 1; - userLoginService.Login("jack", "123456", out bool accountExists, ref retryCount, out UserDto userDto); - userLoginService.LoginAsync("rose", "123456") + var result1 = userLoginService.Login("jack", "123456", 996, out bool accountExists, ref retryCount, out UserDto userDto); + Assert.True(result1); + Assert.True(accountExists); + Assert.Equal(2, retryCount); + Assert.Equal("jack", userDto.RealName); + Assert.Equal("jack", userLoginService.UserName); + Assert.Equal(996, userLoginService.Sault); + + var result2 = userLoginService.LoginAsync("rose", "123456") .ConfigureAwait(false).GetAwaiter().GetResult(); + Assert.True(result2); } [Fact] @@ -30,13 +39,13 @@ public void TestCreateProxy() var userLoginService = (IUserLoginService)Larva.DynamicProxy.DynamicProxyFactory.CreateProxy( typeof(IUserLoginService), new UserLoginService(new UserLoginRepository()), - new Type[] { - typeof(UserLoginCounterInterceptor), - typeof(PerformanceCounterInterceptor) + new IInterceptor[] { + new UserLoginCounterInterceptor(), + new PerformanceCounterInterceptor() }); Assert.Equal($"{typeof(UserLoginService).Name}__DynamicProxyByInstance", userLoginService.GetType().Name); int retryCount = 1; - userLoginService.Login("jack", "123456", out bool accountExists, ref retryCount, out UserDto userDto); + userLoginService.Login("jack", "123456", 996, out bool accountExists, ref retryCount, out UserDto userDto); userLoginService.LoginAsync("rose", "123456") .ConfigureAwait(false).GetAwaiter().GetResult(); } @@ -47,9 +56,9 @@ public void TestCreateProxyType() var userLoginServiceType = Larva.DynamicProxy.DynamicProxyFactory.CreateProxyType( typeof(IUserLoginService), typeof(UserLoginService), - new Type[] { - typeof(UserLoginCounterInterceptor), - typeof(PerformanceCounterInterceptor) + new IInterceptor[] { + new UserLoginCounterInterceptor(), + new PerformanceCounterInterceptor() }); Assert.Equal($"{typeof(UserLoginService).Name}__DynamicProxyByNewObj", userLoginServiceType.Name); var userLoginService = (IUserLoginService)Activator.CreateInstance( @@ -58,7 +67,7 @@ public void TestCreateProxyType() new UserLoginRepository() }); int retryCount = 1; - userLoginService.Login("jack", "123456", out bool accountExists, ref retryCount, out UserDto userDto); + userLoginService.Login("jack", "123456", 996, out bool accountExists, ref retryCount, out UserDto userDto); userLoginService.LoginAsync("rose", "123456") .ConfigureAwait(false).GetAwaiter().GetResult(); } @@ -66,14 +75,15 @@ public void TestCreateProxyType() [Fact] public void TestCreateProxyTypeWhenNoPublicConstructor() { - Assert.Throws(() => { + Assert.Throws(() => + { var userLoginServiceType = Larva.DynamicProxy.DynamicProxyFactory.CreateProxyType( typeof(IUserLoginService), typeof(AnotherUserLoginService), - new Type[] { - typeof(UserLoginCounterInterceptor), - typeof(PerformanceCounterInterceptor) - }); + new IInterceptor[] { + new UserLoginCounterInterceptor(), + new PerformanceCounterInterceptor() + }); }); } } diff --git a/src/DynamicProxyTests/Interceptors/PerformanceCounterInterceptor.cs b/src/Larva.DynamicProxy.Tests/Interceptors/PerformanceCounterInterceptor.cs similarity index 54% rename from src/DynamicProxyTests/Interceptors/PerformanceCounterInterceptor.cs rename to src/Larva.DynamicProxy.Tests/Interceptors/PerformanceCounterInterceptor.cs index 79d503f..cac5d8c 100644 --- a/src/DynamicProxyTests/Interceptors/PerformanceCounterInterceptor.cs +++ b/src/Larva.DynamicProxy.Tests/Interceptors/PerformanceCounterInterceptor.cs @@ -1,27 +1,31 @@ using System; using System.Diagnostics; +using System.Threading; -namespace DynamicProxyTests.Interceptors +namespace Larva.DynamicProxy.Tests.Interceptors { public class PerformanceCounterInterceptor : Larva.DynamicProxy.StandardInterceptor { - private Stopwatch _sw = new Stopwatch(); + private AsyncLocal _sw = new AsyncLocal(); private long _disposeCounter = 0; protected override void PreProceed(Larva.DynamicProxy.IInvocation invocation) { - _sw.Start(); + _sw.Value = new Stopwatch(); + _sw.Value.Start(); } protected override void PostProceed(Larva.DynamicProxy.IInvocation invocation) { - _sw.Stop(); - var elapsedMilliseconds = _sw.ElapsedMilliseconds; - Console.WriteLine($"{invocation.MethodInvocationTarget.DeclaringType.FullName}.{invocation.MethodInvocationTarget.Name} elapsed {elapsedMilliseconds}ms."); + _sw.Value.Stop(); + var elapsedMilliseconds = _sw.Value.ElapsedMilliseconds; + _sw.Value.Reset(); + Console.WriteLine($"{invocation.InvocationTarget.GetType().FullName}.{invocation.MemberName} {invocation.MemberOperateType} elapsed {elapsedMilliseconds}ms."); } public override void Dispose() { + _sw.Value = null; System.Threading.Interlocked.Increment(ref _disposeCounter); Console.WriteLine($"{nameof(PerformanceCounterInterceptor)} disposed {_disposeCounter} times."); } diff --git a/src/DynamicProxyTests/Interceptors/UserLoginCounterInterceptor.cs b/src/Larva.DynamicProxy.Tests/Interceptors/UserLoginCounterInterceptor.cs similarity index 77% rename from src/DynamicProxyTests/Interceptors/UserLoginCounterInterceptor.cs rename to src/Larva.DynamicProxy.Tests/Interceptors/UserLoginCounterInterceptor.cs index 7e9ce1a..4e2c2d0 100644 --- a/src/DynamicProxyTests/Interceptors/UserLoginCounterInterceptor.cs +++ b/src/Larva.DynamicProxy.Tests/Interceptors/UserLoginCounterInterceptor.cs @@ -1,12 +1,12 @@ -using DynamicProxyTests.Application; +using Larva.DynamicProxy.Tests.Application; using System; using System.Collections.Concurrent; -namespace DynamicProxyTests.Interceptors +namespace Larva.DynamicProxy.Tests.Interceptors { public class UserLoginCounterInterceptor : Larva.DynamicProxy.StandardInterceptor { - private static ConcurrentDictionary _counter = new ConcurrentDictionary(); + private ConcurrentDictionary _counter = new ConcurrentDictionary(); private long _disposeCounter = 0; protected override void PreProceed(Larva.DynamicProxy.IInvocation invocation) @@ -19,8 +19,8 @@ protected override void PostProceed(Larva.DynamicProxy.IInvocation invocation) if (invocation.InvocationTarget is IUserLoginService && invocation.MemberType == System.Reflection.MemberTypes.Method && invocation.MemberOperateType == Larva.DynamicProxy.MemberOperateTypes.None - && (invocation.MethodInvocationTarget.Name == nameof(IUserLoginService.Login) - || invocation.MethodInvocationTarget.Name == nameof(IUserLoginService.LoginAsync))) + && (invocation.MemberName == nameof(IUserLoginService.Login) + || invocation.MemberName == nameof(IUserLoginService.LoginAsync))) { var userName = (string)invocation.Arguments[0]; _counter.TryAdd(userName, 0); diff --git a/src/DynamicProxyTests/DynamicProxyTests.csproj b/src/Larva.DynamicProxy.Tests/Larva.DynamicProxy.Tests.csproj similarity index 75% rename from src/DynamicProxyTests/DynamicProxyTests.csproj rename to src/Larva.DynamicProxy.Tests/Larva.DynamicProxy.Tests.csproj index 309c92f..d27196d 100644 --- a/src/DynamicProxyTests/DynamicProxyTests.csproj +++ b/src/Larva.DynamicProxy.Tests/Larva.DynamicProxy.Tests.csproj @@ -1,16 +1,16 @@ - netcoreapp2.1 + netcoreapp3.1 false - 1.0.0 - + + diff --git a/src/DynamicProxyTests/Repositories/IUserLoginRepository.cs b/src/Larva.DynamicProxy.Tests/Repositories/IUserLoginRepository.cs similarity index 57% rename from src/DynamicProxyTests/Repositories/IUserLoginRepository.cs rename to src/Larva.DynamicProxy.Tests/Repositories/IUserLoginRepository.cs index bd6cbd5..f326496 100644 --- a/src/DynamicProxyTests/Repositories/IUserLoginRepository.cs +++ b/src/Larva.DynamicProxy.Tests/Repositories/IUserLoginRepository.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; -namespace DynamicProxyTests.Repositories +namespace Larva.DynamicProxy.Tests.Repositories { public interface IUserLoginRepository { - bool Validate(string userName, string password); + bool Validate(string userName, string password, int sault); Task ValidateAsync(string userName, string password); } diff --git a/src/DynamicProxyTests/Repositories/UserLoginRepository.cs b/src/Larva.DynamicProxy.Tests/Repositories/UserLoginRepository.cs similarity index 53% rename from src/DynamicProxyTests/Repositories/UserLoginRepository.cs rename to src/Larva.DynamicProxy.Tests/Repositories/UserLoginRepository.cs index 90a24d9..257506d 100644 --- a/src/DynamicProxyTests/Repositories/UserLoginRepository.cs +++ b/src/Larva.DynamicProxy.Tests/Repositories/UserLoginRepository.cs @@ -1,14 +1,14 @@ using System; using System.Threading.Tasks; -namespace DynamicProxyTests.Repositories +namespace Larva.DynamicProxy.Tests.Repositories { public class UserLoginRepository : IUserLoginRepository { - public bool Validate(string userName, string password) + public bool Validate(string userName, string password, int sault) { //TODO: validate - // throw new NotSupportedException(nameof(Validate)); + Console.WriteLine($"userName: {userName}, password: {password}, sault: {sault}, Validate: {true}"); return true; } @@ -16,8 +16,7 @@ public async Task ValidateAsync(string userName, string password) { //TODO: validate await Task.Delay(1000); - // throw new NotSupportedException(nameof(ValidateAsync)); - Console.WriteLine($"validate: {true}"); + Console.WriteLine($"userName: {userName}, password: {password}, validateAsync: {true}"); return true; } } diff --git a/src/Larva.DynamicProxy.sln b/src/Larva.DynamicProxy.sln index 07d5c35..40367f3 100644 --- a/src/Larva.DynamicProxy.sln +++ b/src/Larva.DynamicProxy.sln @@ -1,26 +1,48 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicProxyTests", "DynamicProxyTests\DynamicProxyTests.csproj", "{E02BD688-9B48-44F4-84E2-69FC7B9C0D2D}" +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Larva.DynamicProxy", "Larva.DynamicProxy\Larva.DynamicProxy.csproj", "{BEF512AB-A527-4A44-8AB2-3CAC97001E7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Larva.DynamicProxy", "Larva.DynamicProxy\Larva.DynamicProxy.csproj", "{D371C376-53B7-4D1F-9D15-770E3455A7A9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Larva.DynamicProxy.Tests", "Larva.DynamicProxy.Tests\Larva.DynamicProxy.Tests.csproj", "{3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E02BD688-9B48-44F4-84E2-69FC7B9C0D2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E02BD688-9B48-44F4-84E2-69FC7B9C0D2D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E02BD688-9B48-44F4-84E2-69FC7B9C0D2D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E02BD688-9B48-44F4-84E2-69FC7B9C0D2D}.Release|Any CPU.Build.0 = Release|Any CPU - {D371C376-53B7-4D1F-9D15-770E3455A7A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D371C376-53B7-4D1F-9D15-770E3455A7A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D371C376-53B7-4D1F-9D15-770E3455A7A9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D371C376-53B7-4D1F-9D15-770E3455A7A9}.Release|Any CPU.Build.0 = Release|Any CPU + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - version = 1.0.0 + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|x64.ActiveCfg = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|x64.Build.0 = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Debug|x86.Build.0 = Debug|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|Any CPU.Build.0 = Release|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|x64.ActiveCfg = Release|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|x64.Build.0 = Release|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|x86.ActiveCfg = Release|Any CPU + {BEF512AB-A527-4A44-8AB2-3CAC97001E7E}.Release|x86.Build.0 = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|x64.ActiveCfg = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|x64.Build.0 = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|x86.ActiveCfg = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Debug|x86.Build.0 = Debug|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|Any CPU.Build.0 = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|x64.ActiveCfg = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|x64.Build.0 = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|x86.ActiveCfg = Release|Any CPU + {3EACDB5C-8F82-4664-8FDF-47BE7D50E9FC}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Larva.DynamicProxy/DefaultInvocation.cs b/src/Larva.DynamicProxy/DefaultInvocation.cs deleted file mode 100644 index ae25386..0000000 --- a/src/Larva.DynamicProxy/DefaultInvocation.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Larva.DynamicProxy -{ - public sealed class DefaultInvocation : IInvocation - { - private Queue _interceptors; - - public DefaultInvocation(IInterceptor[] interceptors, MemberTypes memberType, string memberName, MemberOperateTypes memberOperateType, object[] arguments, object invocationTarget, MethodInfo methodInvocationTarget, object proxy, MethodInfo method) - { - if (interceptors != null && interceptors.Length > 0) - { - _interceptors = new Queue(interceptors); - } - MemberType = memberType; - MemberName = memberName; - MemberOperateType = memberOperateType; - Arguments = arguments; - InvocationTarget = invocationTarget; - MethodInvocationTarget = methodInvocationTarget; - Proxy = proxy; - Method = method; - ReturnValue = new WrapperObject(); - } - - private DefaultInvocation(IInterceptor[] interceptors, MemberTypes memberType, string memberName, MemberOperateTypes memberOperateType, object[] arguments, object invocationTarget, MethodInfo methodInvocationTarget, object proxy, MethodInfo method, WrapperObject returnValue) - { - if (interceptors != null && interceptors.Length > 0) - { - _interceptors = new Queue(interceptors); - } - MemberType = memberType; - MemberName = memberName; - MemberOperateType = memberOperateType; - Arguments = arguments; - InvocationTarget = invocationTarget; - MethodInvocationTarget = methodInvocationTarget; - Proxy = proxy; - Method = method; - ReturnValue = returnValue; - } - - public MemberTypes MemberType { get; private set; } - - public string MemberName { get; private set; } - - public MemberOperateTypes MemberOperateType { get; private set; } - - public object[] Arguments { get; private set; } - - public object InvocationTarget { get; private set; } - - public MethodInfo MethodInvocationTarget { get; private set; } - - public object Proxy { get; private set; } - - public MethodInfo Method { get; private set; } - - public WrapperObject ReturnValue { get; private set; } - - public void Proceed() - { - if (_interceptors != null && _interceptors.Count > 0) - { - var interceptor = _interceptors.Dequeue(); - interceptor.Intercept(new DefaultInvocation(_interceptors.ToArray(), MemberType, MemberName, MemberOperateType, Arguments, InvocationTarget, MethodInvocationTarget, Proxy, Method, ReturnValue)); - } - else if (MethodInvocationTarget != null) - { - try - { - ReturnValue.Value = MethodInvocationTarget.Invoke(InvocationTarget, Arguments); - } - catch (Exception ex) - { - var ctor = ex.InnerException.GetType().GetTypeInfo().GetConstructor(new Type[] { typeof(string), typeof(Exception) }); - if (ctor != null) - { - throw (Exception)ctor.Invoke(new object[] { ex.InnerException.Message, ex.InnerException }); - } - throw new TargetInvocationException(ex.InnerException.Message, ex.InnerException); - } - } - } - } -} diff --git a/src/Larva.DynamicProxy/DynamicProxyFactory.cs b/src/Larva.DynamicProxy/DynamicProxyFactory.cs index 0914cd3..959d6ff 100644 --- a/src/Larva.DynamicProxy/DynamicProxyFactory.cs +++ b/src/Larva.DynamicProxy/DynamicProxyFactory.cs @@ -8,28 +8,52 @@ namespace Larva.DynamicProxy { + /// + /// 代理类工厂 + /// public sealed class DynamicProxyFactory { private static ConcurrentDictionary _proxyTypeDics = new ConcurrentDictionary(); - public static object CreateProxy(Type interfaceType, object proxiedObj, Type[] interceptorTypes) + /// + /// 创建代理 + /// + /// + /// + /// + /// + public static object CreateProxy(Type interfaceType, object proxiedObj, IInterceptor[] interceptors) { - var proxyType = InternalCreateProxyType(interfaceType, proxiedObj.GetType(), interceptorTypes).ProxyTypeByInstance; + var proxyType = InternalCreateProxyType(interfaceType, proxiedObj.GetType(), interceptors).ProxyTypeByInstance; return Activator.CreateInstance(proxyType, proxiedObj); } - public static TInterface CreateProxy(TInterface proxiedObj, Type[] interceptorTypes) + /// + /// 创建代理 + /// + /// + /// + /// + /// + public static TInterface CreateProxy(TInterface proxiedObj, IInterceptor[] interceptors) where TInterface : class { - return (TInterface)CreateProxy(typeof(TInterface), proxiedObj, interceptorTypes); + return (TInterface)CreateProxy(typeof(TInterface), proxiedObj, interceptors); } - public static Type CreateProxyType(Type interfaceType, Type proxiedType, Type[] interceptorTypes) + /// + /// 创建代理类 + /// + /// + /// + /// + /// + public static Type CreateProxyType(Type interfaceType, Type proxiedType, IInterceptor[] interceptors) { - return InternalCreateProxyType(interfaceType, proxiedType, interceptorTypes).ProxyTypeByNewObj; + return InternalCreateProxyType(interfaceType, proxiedType, interceptors).ProxyTypeByNewObj; } - internal static ProxyTypeWrapper InternalCreateProxyType(Type interfaceType, Type proxiedType, Type[] interceptorTypes) + internal static ProxyTypeWrapper InternalCreateProxyType(Type interfaceType, Type proxiedType, IInterceptor[] interceptors) { var key = new ProxyTypeIdentity(interfaceType, proxiedType); var proxyType = _proxyTypeDics.AddOrUpdate(key, t => @@ -42,24 +66,23 @@ internal static ProxyTypeWrapper InternalCreateProxyType(Type interfaceType, Typ { ProxyTypeByNewObj = new ProxyTypeGenerator(moduleBuilder, interfaceType, proxiedType, ProxyTypeGenerateWay.ByNewObj).Generate(), ProxyTypeByInstance = new ProxyTypeGenerator(moduleBuilder, interfaceType, proxiedType, ProxyTypeGenerateWay.ByInstance).Generate(), - InterceptorTypes = interceptorTypes == null ? null : interceptorTypes.Where(i => typeof(IInterceptor).GetTypeInfo().IsAssignableFrom(i)).Distinct().ToArray() + Interceptors = interceptors }; }, (t, originVal) => { - if (interceptorTypes != null) + if (interceptors != null) { - interceptorTypes = interceptorTypes.Where(i => typeof(IInterceptor).GetTypeInfo().IsAssignableFrom(i)).ToArray(); - List interceptorTypeList = new List(interceptorTypes); - if (_proxyTypeDics[key].InterceptorTypes != null) + var interceptorList = new List(interceptors); + if (_proxyTypeDics[key].Interceptors != null) { - interceptorTypeList.AddRange(_proxyTypeDics[key].InterceptorTypes); + interceptorList.AddRange(_proxyTypeDics[key].Interceptors); } - originVal.InterceptorTypes = interceptorTypeList.Distinct().ToArray(); + originVal.Interceptors = interceptorList.Distinct().ToArray(); } return originVal; }); - proxyType.ProxyTypeByNewObj.GetTypeInfo().GetField(Consts.INTERCEPTOR_TYPES_FIELD_NAME, BindingFlags.Public | BindingFlags.Static | BindingFlags.SetField).SetValue(null, proxyType.InterceptorTypes); - proxyType.ProxyTypeByInstance.GetTypeInfo().GetField(Consts.INTERCEPTOR_TYPES_FIELD_NAME, BindingFlags.Public | BindingFlags.Static | BindingFlags.SetField).SetValue(null, proxyType.InterceptorTypes); + proxyType.ProxyTypeByNewObj.GetField(Consts.INTERCEPTORS_FIELD_NAME, BindingFlags.Public | BindingFlags.Static | BindingFlags.SetField).SetValue(null, proxyType.Interceptors); + proxyType.ProxyTypeByInstance.GetField(Consts.INTERCEPTORS_FIELD_NAME, BindingFlags.Public | BindingFlags.Static | BindingFlags.SetField).SetValue(null, proxyType.Interceptors); return proxyType; } } @@ -70,7 +93,7 @@ internal sealed class ProxyTypeWrapper public Type ProxyTypeByInstance { get; set; } - public Type[] InterceptorTypes { get; set; } + public IInterceptor[] Interceptors { get; set; } } internal struct ProxyTypeIdentity diff --git a/src/Larva.DynamicProxy/Emitters/Consts.cs b/src/Larva.DynamicProxy/Emitters/Consts.cs index 60532d7..ec1c632 100644 --- a/src/Larva.DynamicProxy/Emitters/Consts.cs +++ b/src/Larva.DynamicProxy/Emitters/Consts.cs @@ -1,7 +1,7 @@ namespace Larva.DynamicProxy.Emitters { - public class Consts + internal class Consts { - public const string INTERCEPTOR_TYPES_FIELD_NAME = "InterceptorTypes"; + public const string INTERCEPTORS_FIELD_NAME = "Interceptors"; } } diff --git a/src/Larva.DynamicProxy/Emitters/EmitterHelper.cs b/src/Larva.DynamicProxy/Emitters/EmitterHelper.cs deleted file mode 100644 index e2810d9..0000000 --- a/src/Larva.DynamicProxy/Emitters/EmitterHelper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Linq; - -namespace Larva.DynamicProxy.Emitters -{ - public static class EmitterHelper - { - public static IInterceptor[] CreateInterceptors(Type[] interceptorTypes) - { - return interceptorTypes == null || interceptorTypes.Length == 0 ? null : interceptorTypes.Select(m => (IInterceptor)Activator.CreateInstance(m)).ToArray(); - } - } -} diff --git a/src/Larva.DynamicProxy/Emitters/IMemberEmitter.cs b/src/Larva.DynamicProxy/Emitters/IMemberEmitter.cs index ce775b3..4e62f93 100755 --- a/src/Larva.DynamicProxy/Emitters/IMemberEmitter.cs +++ b/src/Larva.DynamicProxy/Emitters/IMemberEmitter.cs @@ -2,8 +2,15 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 成员 IL生成器 + /// public interface IMemberEmitter { + /// + /// 生成 + /// + /// void Emit(MemberInfo memberInfo); } } diff --git a/src/Larva.DynamicProxy/Emitters/IProxyTypeGeneratorInfo.cs b/src/Larva.DynamicProxy/Emitters/IProxyTypeGeneratorInfo.cs index 109b795..0937e5a 100644 --- a/src/Larva.DynamicProxy/Emitters/IProxyTypeGeneratorInfo.cs +++ b/src/Larva.DynamicProxy/Emitters/IProxyTypeGeneratorInfo.cs @@ -3,18 +3,39 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类生成信息 + /// public interface IProxyTypeGeneratorInfo { + /// + /// 代理类 + /// Type ProxiedType { get; } + /// + /// 类型构建器 + /// TypeBuilder Builder { get; } + /// + /// 代理类生成方式 + /// ProxyTypeGenerateWay Way { get; } + /// + /// 目标对象 字段 + /// FieldBuilder ProxiedObjField { get; } - FieldBuilder InterceptorTypesField { get; } + /// + /// 拦截器 字段 + /// + FieldBuilder InterceptorsField { get; } + /// + /// 生成 + /// Type Generate(); } } \ No newline at end of file diff --git a/src/Larva.DynamicProxy/Emitters/ProxyConstructorEmitter.cs b/src/Larva.DynamicProxy/Emitters/ProxyConstructorEmitter.cs index 56ca95f..ca7c990 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyConstructorEmitter.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyConstructorEmitter.cs @@ -5,15 +5,26 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类构造函数 IL生成器 + /// public sealed class ProxyConstructorEmitter : IMemberEmitter { private IProxyTypeGeneratorInfo _typeGeneratorInfo; + /// + /// 代理构造函数 IL生成器 + /// + /// public ProxyConstructorEmitter(IProxyTypeGeneratorInfo typeGeneratorInfo) { _typeGeneratorInfo = typeGeneratorInfo; } + /// + /// 生成 + /// + /// public void Emit(MemberInfo memberInfo) { if (memberInfo == null) diff --git a/src/Larva.DynamicProxy/Emitters/ProxyEventEmitter.cs b/src/Larva.DynamicProxy/Emitters/ProxyEventEmitter.cs index e5a7e8f..579b004 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyEventEmitter.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyEventEmitter.cs @@ -4,15 +4,26 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类事件 IL生成器 + /// public sealed class ProxyEventEmitter : IMemberEmitter { private IProxyTypeGeneratorInfo _typeGeneratorInfo; + /// + /// 代理类事件 IL生成器 + /// + /// public ProxyEventEmitter(IProxyTypeGeneratorInfo typeGeneratorInfo) { _typeGeneratorInfo = typeGeneratorInfo; } - + + /// + /// 生成 + /// + /// public void Emit(MemberInfo memberInfo) { var proxiedTypeEventInfo = memberInfo as EventInfo; diff --git a/src/Larva.DynamicProxy/Emitters/ProxyMethodEmitter.cs b/src/Larva.DynamicProxy/Emitters/ProxyMethodEmitter.cs index bca7b00..eba8f1e 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyMethodEmitter.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyMethodEmitter.cs @@ -6,19 +6,116 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类方法 IL生成器 + /// public sealed class ProxyMethodEmitter : IMemberEmitter { private IProxyTypeGeneratorInfo _typeGeneratorInfo; + /// + /// 代理类方法 IL生成器 + /// + /// public ProxyMethodEmitter(IProxyTypeGeneratorInfo typeGeneratorInfo) { _typeGeneratorInfo = typeGeneratorInfo; } + /// + /// 生成 + /// + /// public void Emit(MemberInfo memberInfo) { var proxiedTypeMethodInfo = memberInfo as MethodInfo; var parameters = proxiedTypeMethodInfo.GetParameters(); + var proxiedObjField = _typeGeneratorInfo.ProxiedObjField; + var interceptorsField = _typeGeneratorInfo.InterceptorsField; + + #region 私有方法,用于生成目标方法回调 + + var methodFunc = _typeGeneratorInfo.Builder.DefineMethod($"__{proxiedTypeMethodInfo.Name}__", MethodAttributes.Private, typeof(object), new Type[] { typeof(object[]) }); + var methodFuncGenerator = methodFunc.GetILGenerator(); + + // 参数列表Copy到局部变量 + var methodFuncArgumentVarList = new List(); + for (var i = 0; i < parameters.Length; i++) + { + var unwrappedParameterType = parameters[i].ParameterType; + if (parameters[i].ParameterType.IsByRef) + { + unwrappedParameterType = parameters[i].ParameterType.GetElementType(); + } + methodFuncGenerator.Emit(OpCodes.Ldarg_1); + methodFuncGenerator.Emit(OpCodes.Ldc_I4, i); + methodFuncGenerator.Emit(OpCodes.Ldelem_Ref); + if (unwrappedParameterType.IsValueType) + { + methodFuncGenerator.Emit(OpCodes.Unbox_Any, unwrappedParameterType); + } + else if (unwrappedParameterType != typeof(object)) + { + methodFuncGenerator.Emit(OpCodes.Castclass, unwrappedParameterType); + } + var methodFuncArgumentVar = methodFuncGenerator.DeclareLocal(unwrappedParameterType); + methodFuncGenerator.Emit(OpCodes.Stloc, methodFuncArgumentVar); + methodFuncArgumentVarList.Add(methodFuncArgumentVar); + } + + // 获取返回值,无返回类型的方法,返回值设为null + methodFuncGenerator.Emit(OpCodes.Ldarg_0); + methodFuncGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + for (var i = 0; i < parameters.Length; i++) + { + var unwrappedParameterType = methodFuncArgumentVarList[i].LocalType; + if (parameters[i].ParameterType.IsByRef) + { + methodFuncGenerator.Emit(OpCodes.Ldloca_S, methodFuncArgumentVarList[i]); + } + else + { + methodFuncGenerator.Emit(OpCodes.Ldloc, methodFuncArgumentVarList[i]); + } + } + methodFuncGenerator.Emit(OpCodes.Callvirt, proxiedTypeMethodInfo); + var methodFuncReturnValueVal = methodFuncGenerator.DeclareLocal(typeof(object)); + if (proxiedTypeMethodInfo.ReturnType == typeof(void)) + { + methodFuncGenerator.Emit(OpCodes.Ldnull); + } + else if (proxiedTypeMethodInfo.ReturnType.IsValueType) + { + methodFuncGenerator.Emit(OpCodes.Box, proxiedTypeMethodInfo.ReturnType); + } + methodFuncGenerator.Emit(OpCodes.Stloc, methodFuncReturnValueVal); + + // ref/out 参数赋值 + for (var i = 0; i < parameters.Length; i++) + { + if (!parameters[i].ParameterType.IsByRef) + { + continue; + } + var unwrappedParameterType = parameters[i].ParameterType.GetElementType(); + + methodFuncGenerator.Emit(OpCodes.Ldarg_1); + methodFuncGenerator.Emit(OpCodes.Ldc_I4, i); + methodFuncGenerator.Emit(OpCodes.Ldloc, methodFuncArgumentVarList[i]); + if (methodFuncArgumentVarList[i].LocalType.IsValueType) + { + methodFuncGenerator.Emit(OpCodes.Box, methodFuncArgumentVarList[i].LocalType); + } + methodFuncGenerator.Emit(OpCodes.Stelem_Ref); + } + + methodFuncGenerator.Emit(OpCodes.Ldloc, methodFuncReturnValueVal); + methodFuncGenerator.Emit(OpCodes.Ret); + + #endregion + + #region 代理方法 + var method = _typeGeneratorInfo.Builder.DefineMethod(proxiedTypeMethodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, proxiedTypeMethodInfo.ReturnType, parameters.Select(m => m.ParameterType).ToArray()); if (proxiedTypeMethodInfo.IsGenericMethod) { @@ -31,7 +128,7 @@ public void Emit(MemberInfo memberInfo) var genericParameters = method.DefineGenericParameters(genericParameterNameList.ToArray()); for (var i = 0; i < genericArgs.Length; i++) { - var attrs = genericArgs[i].GetTypeInfo().GenericParameterAttributes; + var attrs = genericArgs[i].GenericParameterAttributes; genericParameters[i].SetGenericParameterAttributes(attrs); } } @@ -39,78 +136,80 @@ public void Emit(MemberInfo memberInfo) { method.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name); } - var interceptorTypesField = _typeGeneratorInfo.InterceptorTypesField; - var proxiedObjField = _typeGeneratorInfo.ProxiedObjField; - var generator = method.GetILGenerator(); - var interceptorsVar = generator.DeclareLocal(typeof(IInterceptor[])); - var argObjArrayVar = generator.DeclareLocal(typeof(object[])); - var invocationTargetVar = generator.DeclareLocal(typeof(object)); - var methodInvocationTargetVar = generator.DeclareLocal(typeof(MethodInfo)); - var methodVar = generator.DeclareLocal(typeof(MethodInfo)); - var invocationVar = generator.DeclareLocal(typeof(IInvocation)); - - // Create interceptors - generator.Emit(OpCodes.Ldsfld, interceptorTypesField); - generator.Emit(OpCodes.Call, typeof(EmitterHelper).GetTypeInfo().GetMethod(nameof(EmitterHelper.CreateInterceptors), new Type[] { typeof(Type[]) })); - generator.Emit(OpCodes.Stloc, interceptorsVar); - - // Newarr argument. - generator.Emit(OpCodes.Ldc_I4, parameters.Length); - generator.Emit(OpCodes.Newarr, typeof(object)); + var methodGenerator = method.GetILGenerator(); + + // 创建参数类型列表的局部变量 + methodGenerator.Emit(OpCodes.Ldc_I4, parameters.Length); + methodGenerator.Emit(OpCodes.Newarr, typeof(Type)); for (var i = 0; i < parameters.Length; i++) { - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldarg, i + 1); + methodGenerator.Emit(OpCodes.Dup); + methodGenerator.Emit(OpCodes.Ldc_I4, i); var unwrappedParameterType = parameters[i].ParameterType; if (parameters[i].ParameterType.IsByRef) { unwrappedParameterType = parameters[i].ParameterType.GetElementType(); - generator.Emit(OpCodes.Ldind_Ref); } - if (unwrappedParameterType.GetTypeInfo().IsValueType) + methodGenerator.Emit(OpCodes.Ldtoken, unwrappedParameterType); + methodGenerator.Emit(OpCodes.Stelem_Ref); + } + var argArgumentTypeArrayVar = methodGenerator.DeclareLocal(typeof(Type[])); + methodGenerator.Emit(OpCodes.Stloc, argArgumentTypeArrayVar); + + // 创建参数列表的局部变量 + methodGenerator.Emit(OpCodes.Ldc_I4, parameters.Length); + methodGenerator.Emit(OpCodes.Newarr, typeof(object)); + for (var i = 0; i < parameters.Length; i++) + { + methodGenerator.Emit(OpCodes.Dup); + methodGenerator.Emit(OpCodes.Ldc_I4, i); + methodGenerator.Emit(OpCodes.Ldarg, i + 1); + var unwrappedParameterType = parameters[i].ParameterType; + if (parameters[i].ParameterType.IsByRef) { - generator.Emit(OpCodes.Box, unwrappedParameterType); + unwrappedParameterType = parameters[i].ParameterType.GetElementType(); + methodGenerator.Emit(OpCodes.Ldind_Ref); + } + if (unwrappedParameterType.IsValueType) + { + methodGenerator.Emit(OpCodes.Box, unwrappedParameterType); } - generator.Emit(OpCodes.Stelem_Ref); + methodGenerator.Emit(OpCodes.Stelem_Ref); } - generator.Emit(OpCodes.Stloc, argObjArrayVar); - - // Get proxiedObj - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, proxiedObjField); - generator.Emit(OpCodes.Stloc, invocationTargetVar); - - // Get proxiedObj's method - generator.Emit(OpCodes.Ldtoken, proxiedTypeMethodInfo); - generator.Emit(OpCodes.Ldtoken, proxiedTypeMethodInfo.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodInvocationTargetVar); - - // Get proxy's method - generator.Emit(OpCodes.Ldtoken, method); - generator.Emit(OpCodes.Ldtoken, method.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodVar); - - // Newobj DefaultInvocation - generator.Emit(OpCodes.Ldloc, interceptorsVar); - generator.Emit(OpCodes.Ldc_I4_8); - generator.Emit(OpCodes.Ldstr, proxiedTypeMethodInfo.Name); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Ldloc, argObjArrayVar); - generator.Emit(OpCodes.Ldloc, invocationTargetVar); - generator.Emit(OpCodes.Ldloc, methodInvocationTargetVar); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldloc, methodVar); - generator.Emit(OpCodes.Newobj, typeof(DefaultInvocation).GetTypeInfo().GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(MemberTypes), typeof(string), typeof(MemberOperateTypes), typeof(object[]), typeof(object), typeof(MethodInfo), typeof(object), typeof(MethodInfo) })); - generator.Emit(OpCodes.Stloc, invocationVar); + var argArgumentArrayVar = methodGenerator.DeclareLocal(typeof(object[])); + methodGenerator.Emit(OpCodes.Stloc, argArgumentArrayVar); + + #region 创建 MethodInvocation + + methodGenerator.Emit(OpCodes.Ldsfld, interceptorsField);// 拦截器 + methodGenerator.Emit(OpCodes.Ldstr, proxiedTypeMethodInfo.Name);// 方法名 + methodGenerator.Emit(OpCodes.Ldloc, argArgumentTypeArrayVar);// 参数类型列表 + methodGenerator.Emit(OpCodes.Ldtoken, proxiedTypeMethodInfo.ReturnType);// 返回类型 + + // 目标对象 + methodGenerator.Emit(OpCodes.Ldarg_0); + methodGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + + // 目标方法回调 + methodGenerator.Emit(OpCodes.Ldarg_0); + methodGenerator.Emit(OpCodes.Ldftn, methodFunc); + methodGenerator.Emit(OpCodes.Newobj, typeof(Func).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); + + methodGenerator.Emit(OpCodes.Ldarg_0);// 代理对象 + methodGenerator.Emit(OpCodes.Ldloc, argArgumentArrayVar);// 参数列表 + + methodGenerator.Emit(OpCodes.Newobj, typeof(MethodInvocation).GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(string), typeof(Type[]), typeof(Type), typeof(object), typeof(Func), typeof(object), typeof(object[]) })); + + var invocationVar = methodGenerator.DeclareLocal(typeof(IInvocation)); + methodGenerator.Emit(OpCodes.Stloc, invocationVar); + + #endregion // invocation.Proceed - generator.Emit(OpCodes.Ldloc, invocationVar); - generator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetTypeInfo().GetMethod(nameof(IInvocation.Proceed))); + methodGenerator.Emit(OpCodes.Ldloc, invocationVar); + methodGenerator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetMethod(nameof(IInvocation.Proceed))); - // assign ref/out parameter + // ref/out 参数赋值 for (var i = 0; i < parameters.Length; i++) { if (!parameters[i].ParameterType.IsByRef) @@ -118,32 +217,34 @@ public void Emit(MemberInfo memberInfo) continue; } var unwrappedParameterType = parameters[i].ParameterType.GetElementType(); - generator.Emit(OpCodes.Ldarg, i + 1); - generator.Emit(OpCodes.Ldloc, argObjArrayVar); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldelem_Ref); - if (unwrappedParameterType.GetTypeInfo().IsValueType) + methodGenerator.Emit(OpCodes.Ldarg, i + 1); + methodGenerator.Emit(OpCodes.Ldloc, argArgumentArrayVar); + methodGenerator.Emit(OpCodes.Ldc_I4, i); + methodGenerator.Emit(OpCodes.Ldelem_Ref); + if (unwrappedParameterType.IsValueType) { - generator.Emit(OpCodes.Unbox_Any, unwrappedParameterType); + methodGenerator.Emit(OpCodes.Unbox_Any, unwrappedParameterType); } - generator.Emit(OpCodes.Stind_Ref); + methodGenerator.Emit(OpCodes.Stind_Ref); } + // 返回 if (proxiedTypeMethodInfo.ReturnType != typeof(void)) { - generator.Emit(OpCodes.Ldloc, invocationVar); - generator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetTypeInfo().GetProperty(nameof(IInvocation.ReturnValue)).GetMethod); - generator.Emit(OpCodes.Callvirt, typeof(WrapperObject).GetTypeInfo().GetProperty(nameof(WrapperObject.Value)).GetMethod); - if (proxiedTypeMethodInfo.ReturnType.GetTypeInfo().IsValueType) + methodGenerator.Emit(OpCodes.Ldloc, invocationVar); + methodGenerator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetProperty(nameof(IInvocation.ReturnValue)).GetMethod); + if (proxiedTypeMethodInfo.ReturnType.IsValueType) { - generator.Emit(OpCodes.Unbox_Any, proxiedTypeMethodInfo.ReturnType); + methodGenerator.Emit(OpCodes.Unbox_Any, proxiedTypeMethodInfo.ReturnType); } else { - generator.Emit(OpCodes.Castclass, proxiedTypeMethodInfo.ReturnType); + methodGenerator.Emit(OpCodes.Castclass, proxiedTypeMethodInfo.ReturnType); } } - generator.Emit(OpCodes.Ret); + methodGenerator.Emit(OpCodes.Ret); + + #endregion } } } diff --git a/src/Larva.DynamicProxy/Emitters/ProxyPropertyEmitter.cs b/src/Larva.DynamicProxy/Emitters/ProxyPropertyEmitter.cs index 22f5916..9e82b04 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyPropertyEmitter.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyPropertyEmitter.cs @@ -4,15 +4,26 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类属性 IL生成器 + /// public sealed class ProxyPropertyEmitter : IMemberEmitter { private IProxyTypeGeneratorInfo _typeGeneratorInfo; + /// + /// 代理类属性 IL生成器 + /// + /// public ProxyPropertyEmitter(IProxyTypeGeneratorInfo typeGeneratorInfo) { _typeGeneratorInfo = typeGeneratorInfo; } + /// + /// 生成 + /// + /// public void Emit(MemberInfo memberInfo) { var proxiedTypePropertyInfo = memberInfo as PropertyInfo; @@ -24,138 +35,161 @@ public void Emit(MemberInfo memberInfo) MethodAttributes.NewSlot | MethodAttributes.Final; - var interceptorTypesField = _typeGeneratorInfo.InterceptorTypesField; + var interceptorsField = _typeGeneratorInfo.InterceptorsField; var proxiedObjField = _typeGeneratorInfo.ProxiedObjField; if (proxiedTypePropertyInfo.CanRead) { - var getMethod = _typeGeneratorInfo.Builder.DefineMethod("get_" + proxiedTypePropertyInfo.Name, getSetAttr, proxiedTypePropertyInfo.PropertyType, Type.EmptyTypes); - var generator = getMethod.GetILGenerator(); - var interceptorsVar = generator.DeclareLocal(typeof(IInterceptor[])); - var invocationTargetVar = generator.DeclareLocal(typeof(object)); - var methodInvocationTargetVar = generator.DeclareLocal(typeof(MethodInfo)); - var methodVar = generator.DeclareLocal(typeof(MethodInfo)); - var invocationVar = generator.DeclareLocal(typeof(IInvocation)); - - // Create interceptors - generator.Emit(OpCodes.Ldsfld, interceptorTypesField); - generator.Emit(OpCodes.Call, typeof(EmitterHelper).GetTypeInfo().GetMethod(nameof(EmitterHelper.CreateInterceptors), new Type[] { typeof(Type[]) })); - generator.Emit(OpCodes.Stloc, interceptorsVar); - - // Get proxiedObj - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, proxiedObjField); - generator.Emit(OpCodes.Stloc, invocationTargetVar); - - // Get proxiedObj's method - generator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.GetMethod); - generator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.GetMethod.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodInvocationTargetVar); - - // Get proxy's method - generator.Emit(OpCodes.Ldtoken, getMethod); - generator.Emit(OpCodes.Ldtoken, getMethod.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodVar); - - // Newobj DefaultInvocation - generator.Emit(OpCodes.Ldloc, interceptorsVar); - generator.Emit(OpCodes.Ldc_I4, (int)MemberTypes.Property); - generator.Emit(OpCodes.Ldstr, proxiedTypePropertyInfo.Name); - generator.Emit(OpCodes.Ldc_I4_1); - generator.Emit(OpCodes.Ldnull); - generator.Emit(OpCodes.Ldloc, invocationTargetVar); - generator.Emit(OpCodes.Ldloc, methodInvocationTargetVar); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldloc, methodVar); - generator.Emit(OpCodes.Newobj, typeof(DefaultInvocation).GetTypeInfo().GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(MemberTypes), typeof(string), typeof(MemberOperateTypes), typeof(object[]), typeof(object), typeof(MethodInfo), typeof(object), typeof(MethodInfo) })); - generator.Emit(OpCodes.Stloc, invocationVar); + #region 私有方法,用于生成目标方法回调 + + var getMethodFunc = _typeGeneratorInfo.Builder.DefineMethod($"__get_{proxiedTypePropertyInfo.Name}__", MethodAttributes.Private, typeof(object), Type.EmptyTypes); + var getMethodFuncGenerator = getMethodFunc.GetILGenerator(); + + // 获取返回值,无返回类型的方法,返回值设为null + getMethodFuncGenerator.Emit(OpCodes.Ldarg_0); + getMethodFuncGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + + getMethodFuncGenerator.Emit(OpCodes.Callvirt, proxiedTypePropertyInfo.GetMethod); + var getMethodFuncReturnValueVal = getMethodFuncGenerator.DeclareLocal(typeof(object)); + if (proxiedTypePropertyInfo.PropertyType.IsValueType) + { + getMethodFuncGenerator.Emit(OpCodes.Box, proxiedTypePropertyInfo.PropertyType); + } + getMethodFuncGenerator.Emit(OpCodes.Stloc, getMethodFuncReturnValueVal); + + getMethodFuncGenerator.Emit(OpCodes.Ldloc, getMethodFuncReturnValueVal); + getMethodFuncGenerator.Emit(OpCodes.Ret); + + #endregion + + #region 代理方法 + + var getMethod = _typeGeneratorInfo.Builder.DefineMethod("get_" + proxiedTypePropertyInfo.Name, getSetAttr, proxiedTypePropertyInfo.PropertyType, null); + var getMethodGenerator = getMethod.GetILGenerator(); + + #region 创建 MethodInvocation + + getMethodGenerator.Emit(OpCodes.Ldsfld, interceptorsField);// 拦截器 + getMethodGenerator.Emit(OpCodes.Ldstr, proxiedTypePropertyInfo.Name);// 属性名 + getMethodGenerator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.PropertyType);// 属性类型 + + // 目标对象 + getMethodGenerator.Emit(OpCodes.Ldarg_0); + getMethodGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + + // 目标方法回调 + getMethodGenerator.Emit(OpCodes.Ldarg_0); + getMethodGenerator.Emit(OpCodes.Ldftn, getMethodFunc); + getMethodGenerator.Emit(OpCodes.Newobj, typeof(Func).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); + + getMethodGenerator.Emit(OpCodes.Ldarg_0);// 代理对象 + + getMethodGenerator.Emit(OpCodes.Newobj, typeof(PropertyGetInvocation).GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(string), typeof(Type), typeof(object), typeof(Func), typeof(object) })); + + var invocationVar = getMethodGenerator.DeclareLocal(typeof(IInvocation)); + getMethodGenerator.Emit(OpCodes.Stloc, invocationVar); + + #endregion // invocation.Proceed - generator.Emit(OpCodes.Ldloc, invocationVar); - generator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetTypeInfo().GetMethod(nameof(IInvocation.Proceed))); - - var returnObj = generator.DeclareLocal(proxiedTypePropertyInfo.PropertyType); - generator.Emit(OpCodes.Ldloc, invocationVar); - generator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetTypeInfo().GetProperty(nameof(IInvocation.ReturnValue)).GetMethod); - generator.Emit(OpCodes.Callvirt, typeof(WrapperObject).GetTypeInfo().GetProperty(nameof(WrapperObject.Value)).GetMethod); - if (proxiedTypePropertyInfo.PropertyType.GetTypeInfo().IsValueType) + getMethodGenerator.Emit(OpCodes.Ldloc, invocationVar); + getMethodGenerator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetMethod(nameof(IInvocation.Proceed))); + + // 返回 + getMethodGenerator.Emit(OpCodes.Ldloc, invocationVar); + getMethodGenerator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetProperty(nameof(IInvocation.ReturnValue)).GetMethod); + if (proxiedTypePropertyInfo.PropertyType.IsValueType) { - generator.Emit(OpCodes.Unbox_Any, proxiedTypePropertyInfo.PropertyType); + getMethodGenerator.Emit(OpCodes.Unbox_Any, proxiedTypePropertyInfo.PropertyType); } else { - generator.Emit(OpCodes.Castclass, proxiedTypePropertyInfo.PropertyType); + getMethodGenerator.Emit(OpCodes.Castclass, proxiedTypePropertyInfo.PropertyType); } - generator.Emit(OpCodes.Ret); + getMethodGenerator.Emit(OpCodes.Ret); property.SetGetMethod(getMethod); + + #endregion } if (proxiedTypePropertyInfo.CanWrite) { + #region 私有方法,用于生成目标方法回调 + + var setMethodFunc = _typeGeneratorInfo.Builder.DefineMethod($"__set_{proxiedTypePropertyInfo.Name}__", MethodAttributes.Private, typeof(void), new Type[] { typeof(object) }); + var setMethodFuncGenerator = setMethodFunc.GetILGenerator(); + + // 参数列表Copy到局部变量 + setMethodFuncGenerator.Emit(OpCodes.Ldarg_1); + if (proxiedTypePropertyInfo.PropertyType.IsValueType) + { + setMethodFuncGenerator.Emit(OpCodes.Unbox_Any, proxiedTypePropertyInfo.PropertyType); + } + else if (proxiedTypePropertyInfo.PropertyType != typeof(object)) + { + setMethodFuncGenerator.Emit(OpCodes.Castclass, proxiedTypePropertyInfo.PropertyType); + } + var methodFuncArgumentVar = setMethodFuncGenerator.DeclareLocal(proxiedTypePropertyInfo.PropertyType); + setMethodFuncGenerator.Emit(OpCodes.Stloc, methodFuncArgumentVar); + + // 获取返回值,无返回类型的方法,返回值设为null + setMethodFuncGenerator.Emit(OpCodes.Ldarg_0); + setMethodFuncGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + setMethodFuncGenerator.Emit(OpCodes.Ldloc, methodFuncArgumentVar); + setMethodFuncGenerator.Emit(OpCodes.Callvirt, proxiedTypePropertyInfo.SetMethod); + setMethodFuncGenerator.Emit(OpCodes.Ret); + + #endregion + + #region 代理方法 + var setMethod = _typeGeneratorInfo.Builder.DefineMethod("set_" + proxiedTypePropertyInfo.Name, getSetAttr, null, new Type[] { proxiedTypePropertyInfo.PropertyType }); - var generator = setMethod.GetILGenerator(); - var interceptorsVar = generator.DeclareLocal(typeof(IInterceptor[])); - var argObjArrayVar = generator.DeclareLocal(typeof(object[])); - var invocationTargetVar = generator.DeclareLocal(typeof(object)); - var methodInvocationTargetVar = generator.DeclareLocal(typeof(MethodInfo)); - var methodVar = generator.DeclareLocal(typeof(MethodInfo)); - var invocationVar = generator.DeclareLocal(typeof(IInvocation)); - - // Create interceptors - generator.Emit(OpCodes.Ldsfld, interceptorTypesField); - generator.Emit(OpCodes.Call, typeof(EmitterHelper).GetTypeInfo().GetMethod(nameof(EmitterHelper.CreateInterceptors), new Type[] { typeof(Type[]) })); - generator.Emit(OpCodes.Stloc, interceptorsVar); - - // Newarr argument. - generator.Emit(OpCodes.Ldc_I4_1); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Ldarg_1); - if (proxiedTypePropertyInfo.PropertyType.GetTypeInfo().IsValueType) + var methodParameter = proxiedTypePropertyInfo.SetMethod.GetParameters()[0]; + setMethod.DefineParameter(1, methodParameter.Attributes, methodParameter.Name); + var setMethodGenerator = setMethod.GetILGenerator(); + + // 创建参数列表的局部变量 + setMethodGenerator.Emit(OpCodes.Ldarg_1); + if (proxiedTypePropertyInfo.DeclaringType.IsValueType) { - generator.Emit(OpCodes.Box, proxiedTypePropertyInfo.PropertyType); + setMethodGenerator.Emit(OpCodes.Box, proxiedTypePropertyInfo.DeclaringType); } - generator.Emit(OpCodes.Stelem_Ref); - generator.Emit(OpCodes.Stloc, argObjArrayVar); - - // Get proxiedObj - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, proxiedObjField); - generator.Emit(OpCodes.Stloc, invocationTargetVar); - - // Get proxiedObj's method - generator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.SetMethod); - generator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.SetMethod.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodInvocationTargetVar); - - // Get proxy's method - generator.Emit(OpCodes.Ldtoken, setMethod); - generator.Emit(OpCodes.Ldtoken, setMethod.DeclaringType); - generator.Emit(OpCodes.Call, typeof(MethodBase).GetTypeInfo().GetMethod(nameof(MethodBase.GetMethodFromHandle), new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); - generator.Emit(OpCodes.Stloc, methodVar); - - // Newobj DefaultInvocation - generator.Emit(OpCodes.Ldloc, interceptorsVar); - generator.Emit(OpCodes.Ldc_I4, (int)MemberTypes.Property); - generator.Emit(OpCodes.Ldstr, proxiedTypePropertyInfo.Name); - generator.Emit(OpCodes.Ldc_I4_2); - generator.Emit(OpCodes.Ldloc, argObjArrayVar); - generator.Emit(OpCodes.Ldloc, invocationTargetVar); - generator.Emit(OpCodes.Ldloc, methodInvocationTargetVar); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldloc, methodVar); - generator.Emit(OpCodes.Newobj, typeof(DefaultInvocation).GetTypeInfo().GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(MemberTypes), typeof(string), typeof(MemberOperateTypes), typeof(object[]), typeof(object), typeof(MethodInfo), typeof(object), typeof(MethodInfo) })); - generator.Emit(OpCodes.Stloc, invocationVar); + var argumentVar = setMethodGenerator.DeclareLocal(typeof(object)); + setMethodGenerator.Emit(OpCodes.Stloc, argumentVar); + + #region 创建 MethodInvocation + + setMethodGenerator.Emit(OpCodes.Ldsfld, interceptorsField);// 拦截器 + setMethodGenerator.Emit(OpCodes.Ldstr, proxiedTypePropertyInfo.Name);// 属性名 + setMethodGenerator.Emit(OpCodes.Ldtoken, proxiedTypePropertyInfo.PropertyType);// 属性类型 + + // 目标对象 + setMethodGenerator.Emit(OpCodes.Ldarg_0); + setMethodGenerator.Emit(OpCodes.Ldfld, proxiedObjField); + + // 目标方法回调 + setMethodGenerator.Emit(OpCodes.Ldarg_0); + setMethodGenerator.Emit(OpCodes.Ldftn, setMethodFunc); + setMethodGenerator.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); + + setMethodGenerator.Emit(OpCodes.Ldarg_0);// 代理对象 + setMethodGenerator.Emit(OpCodes.Ldloc, argumentVar);// 参数 + + setMethodGenerator.Emit(OpCodes.Newobj, typeof(PropertySetInvocation).GetConstructor(new Type[] { typeof(IInterceptor[]), typeof(string), typeof(Type), typeof(object), typeof(Action), typeof(object), typeof(object) })); + + var invocationVar = setMethodGenerator.DeclareLocal(typeof(IInvocation)); + setMethodGenerator.Emit(OpCodes.Stloc, invocationVar); + + #endregion // invocation.Proceed - generator.Emit(OpCodes.Ldloc, invocationVar); - generator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetTypeInfo().GetMethod(nameof(IInvocation.Proceed))); + setMethodGenerator.Emit(OpCodes.Ldloc, invocationVar); + setMethodGenerator.Emit(OpCodes.Callvirt, typeof(IInvocation).GetMethod(nameof(IInvocation.Proceed))); - generator.Emit(OpCodes.Ret); + // 返回 + setMethodGenerator.Emit(OpCodes.Ret); property.SetSetMethod(setMethod); + + #endregion } } } diff --git a/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerateWay.cs b/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerateWay.cs index e54d320..85e8d43 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerateWay.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerateWay.cs @@ -1,9 +1,18 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类生成方式 + /// public enum ProxyTypeGenerateWay { + /// + /// 按新对象生成 + /// ByNewObj = 0, + /// + /// 按实例生成 + /// ByInstance = 1 } } diff --git a/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerator.cs b/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerator.cs index 8a039bd..a54701d 100644 --- a/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerator.cs +++ b/src/Larva.DynamicProxy/Emitters/ProxyTypeGenerator.cs @@ -6,23 +6,33 @@ namespace Larva.DynamicProxy.Emitters { + /// + /// 代理类生成器 + /// public sealed class ProxyTypeGenerator : IProxyTypeGeneratorInfo { private Type _proxiedInterfaceType; private Type _cachedType; + /// + /// + /// + /// + /// + /// + /// public ProxyTypeGenerator(ModuleBuilder moduleBuilder, Type proxiedInterfaceType, Type proxiedType, ProxyTypeGenerateWay way) { - if (!proxiedInterfaceType.GetTypeInfo().IsInterface) + if (!proxiedInterfaceType.IsInterface) { throw new InvalidProxiedInterfaceTypeException($"Unable to cast object of type '{proxiedType}' to type '{proxiedInterfaceType}"); } - if (!proxiedInterfaceType.GetTypeInfo().IsAssignableFrom(proxiedType)) + if (!proxiedInterfaceType.IsAssignableFrom(proxiedType)) { throw new InvalidCastException($"Unable to cast object of type '{proxiedType}' to type '{proxiedInterfaceType}"); } if (way == ProxyTypeGenerateWay.ByNewObj - && proxiedType.GetTypeInfo().GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance).Length == 0) + && proxiedType.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance).Length == 0) { throw new InvalidProxiedTypeException($"Type {proxiedType} that no public constructor in, cann't use '{nameof(ProxyTypeGenerateWay)}.{ProxyTypeGenerateWay.ByNewObj}'"); } @@ -35,19 +45,38 @@ public ProxyTypeGenerator(ModuleBuilder moduleBuilder, Type proxiedInterfaceType Way = way; ProxiedObjField = Builder.DefineField("_proxiedObj", proxiedInterfaceType, FieldAttributes.Private); - InterceptorTypesField = Builder.DefineField(Consts.INTERCEPTOR_TYPES_FIELD_NAME, typeof(Type[]), FieldAttributes.Public | FieldAttributes.Static); + InterceptorsField = Builder.DefineField(Consts.INTERCEPTORS_FIELD_NAME, typeof(IInterceptor[]), FieldAttributes.Public | FieldAttributes.Static); } + /// + /// + /// public Type ProxiedType { get; private set; } + /// + /// + /// public TypeBuilder Builder { get; private set; } + /// + /// + /// public ProxyTypeGenerateWay Way { get; private set; } + /// + /// + /// public FieldBuilder ProxiedObjField { get; private set; } - public FieldBuilder InterceptorTypesField { get; private set; } + /// + /// + /// + public FieldBuilder InterceptorsField { get; private set; } + /// + /// + /// + /// public Type Generate() { if (_cachedType == null) @@ -55,7 +84,7 @@ public Type Generate() // constructor if (Way == ProxyTypeGenerateWay.ByNewObj) { - var cctors = ProxiedType.GetTypeInfo().GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance); + var cctors = ProxiedType.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance); foreach (var cctor in cctors) { new ProxyConstructorEmitter(this).Emit(cctor); @@ -67,7 +96,7 @@ public Type Generate() } AddMethods(_proxiedInterfaceType, ProxiedType, AddEvents(_proxiedInterfaceType, ProxiedType), AddProperties(_proxiedInterfaceType, ProxiedType)); - foreach (var interfaceType in _proxiedInterfaceType.GetTypeInfo().GetInterfaces()) + foreach (var interfaceType in _proxiedInterfaceType.GetInterfaces()) { AddMethods(interfaceType, ProxiedType, AddEvents(interfaceType, ProxiedType), AddProperties(interfaceType, ProxiedType)); } @@ -90,7 +119,7 @@ private bool IsTypeArrayEqual(Type[] array1, Type[] array2) return false; for (var i = 0; i < array1.Length; i++) { - if (array1[i].GetTypeInfo().IsGenericType && array2[i].GetTypeInfo().IsGenericType) + if (array1[i].IsGenericType && array2[i].IsGenericType) { if (!array1[i].GetGenericTypeDefinition().Equals(array2[i].GetGenericTypeDefinition())) return false; @@ -113,7 +142,7 @@ private bool IsMethodSignutureEqual(MethodInfo method1, MethodInfo method2) private List AddEvents(Type interfaceType, Type proxiedType) { var eventMethodList = new List(); - foreach (var interfaceEventInfo in interfaceType.GetTypeInfo().GetEvents()) + foreach (var interfaceEventInfo in interfaceType.GetEvents()) { if (interfaceEventInfo.AddMethod != null) { @@ -123,7 +152,7 @@ private List AddEvents(Type interfaceType, Type proxiedType) { eventMethodList.Add(interfaceEventInfo.RemoveMethod); } - new ProxyEventEmitter(this).Emit(proxiedType.GetTypeInfo().GetEvent(interfaceEventInfo.Name)); + new ProxyEventEmitter(this).Emit(proxiedType.GetEvent(interfaceEventInfo.Name)); } return eventMethodList; } @@ -131,7 +160,7 @@ private List AddEvents(Type interfaceType, Type proxiedType) private List AddProperties(Type interfaceType, Type proxiedType) { var propertyMethodList = new List(); - foreach (var interfacePropertyInfo in interfaceType.GetTypeInfo().GetProperties()) + foreach (var interfacePropertyInfo in interfaceType.GetProperties()) { if (interfacePropertyInfo.CanRead) { @@ -144,27 +173,27 @@ private List AddProperties(Type interfaceType, Type proxiedType) #if DEBUG Console.WriteLine($"Property: {interfacePropertyInfo.PropertyType.Name} {interfacePropertyInfo.Name}"); #endif - new ProxyPropertyEmitter(this).Emit(proxiedType.GetTypeInfo().GetProperty(interfacePropertyInfo.Name, interfacePropertyInfo.PropertyType, interfacePropertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray())); + new ProxyPropertyEmitter(this).Emit(proxiedType.GetProperty(interfacePropertyInfo.Name, interfacePropertyInfo.PropertyType, interfacePropertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray())); } return propertyMethodList; } private void AddMethods(Type interfaceType, Type proxiedType, IList eventMethodList, IList propertyMethodList) { - foreach (var interfaceMethodInfo in interfaceType.GetTypeInfo().GetMethods()) + foreach (var interfaceMethodInfo in interfaceType.GetMethods()) { if (!propertyMethodList.Contains(interfaceMethodInfo) && !eventMethodList.Contains(interfaceMethodInfo)) { - var methodInfo = proxiedType.GetTypeInfo().GetMethods().FirstOrDefault(m => IsMethodSignutureEqual(m, interfaceMethodInfo)); + var methodInfo = proxiedType.GetMethods().FirstOrDefault(m => IsMethodSignutureEqual(m, interfaceMethodInfo)); if (methodInfo == null) { - var baseType = proxiedType.GetTypeInfo().BaseType; + var baseType = proxiedType.BaseType; while (baseType != null) { - methodInfo = baseType.GetTypeInfo().GetMethods().FirstOrDefault(m => IsMethodSignutureEqual(m, interfaceMethodInfo)); + methodInfo = baseType.GetMethods().FirstOrDefault(m => IsMethodSignutureEqual(m, interfaceMethodInfo)); if (methodInfo != null) break; - baseType = baseType.GetTypeInfo().BaseType; + baseType = baseType.BaseType; } } #if DEBUG diff --git a/src/Larva.DynamicProxy/IInterceptor.cs b/src/Larva.DynamicProxy/IInterceptor.cs index 9eca84c..231d7c1 100755 --- a/src/Larva.DynamicProxy/IInterceptor.cs +++ b/src/Larva.DynamicProxy/IInterceptor.cs @@ -1,7 +1,14 @@ namespace Larva.DynamicProxy { + /// + /// 拦截器 + /// public interface IInterceptor { + /// + /// 拦截 + /// + /// void Intercept(IInvocation invocation); } } diff --git a/src/Larva.DynamicProxy/IInvocation.cs b/src/Larva.DynamicProxy/IInvocation.cs index 58ee8cc..118eeda 100644 --- a/src/Larva.DynamicProxy/IInvocation.cs +++ b/src/Larva.DynamicProxy/IInvocation.cs @@ -1,27 +1,61 @@ -using System.Reflection; +using System; +using System.Reflection; namespace Larva.DynamicProxy { + /// + /// 调用 + /// public interface IInvocation { + /// + /// 成员类型 + /// MemberTypes MemberType { get; } + /// + /// 成员名称 + /// string MemberName { get; } + /// + /// 成员操作类型 + /// MemberOperateTypes MemberOperateType { get; } - object InvocationTarget { get; } + /// + /// 参数类型 + /// + Type[] ArgumentTypes { get; } - MethodInfo MethodInvocationTarget { get; } + /// + /// 返回值类型 + /// + Type ReturnValueType { get; } - object Proxy { get; } + /// + /// 调用目标对象 + /// + object InvocationTarget { get; } - MethodInfo Method { get; } + /// + /// 代理对象 + /// + object Proxy { get; } + /// + /// 参数 + /// object[] Arguments { get; } - WrapperObject ReturnValue { get; } + /// + /// 返回值 + /// + object ReturnValue { get; } + /// + /// 处理 + /// void Proceed(); } } diff --git a/src/Larva.DynamicProxy/InvalidProxiedInterfaceTypeException.cs b/src/Larva.DynamicProxy/InvalidProxiedInterfaceTypeException.cs index b8e591a..6af997e 100644 --- a/src/Larva.DynamicProxy/InvalidProxiedInterfaceTypeException.cs +++ b/src/Larva.DynamicProxy/InvalidProxiedInterfaceTypeException.cs @@ -2,12 +2,29 @@ namespace Larva.DynamicProxy { + /// + /// 非法代理接口类型异常 + /// public class InvalidProxiedInterfaceTypeException : Exception { + /// + /// 非法代理接口类型异常 + /// public InvalidProxiedInterfaceTypeException() { } + /// + /// 非法代理接口类型异常 + /// + /// + /// public InvalidProxiedInterfaceTypeException(string message) : base(message) { } - public InvalidProxiedInterfaceTypeException(string message, Exception innerException):base(message, innerException) { } + /// + /// 非法代理接口类型异常 + /// + /// + /// + /// + public InvalidProxiedInterfaceTypeException(string message, Exception innerException) : base(message, innerException) { } } } diff --git a/src/Larva.DynamicProxy/InvalidProxiedTypeException.cs b/src/Larva.DynamicProxy/InvalidProxiedTypeException.cs index a52f4a8..acc18ad 100644 --- a/src/Larva.DynamicProxy/InvalidProxiedTypeException.cs +++ b/src/Larva.DynamicProxy/InvalidProxiedTypeException.cs @@ -2,12 +2,29 @@ namespace Larva.DynamicProxy { + /// + /// 非法代理类型异常 + /// public class InvalidProxiedTypeException : Exception { + /// + /// 非法代理类型异常 + /// public InvalidProxiedTypeException() { } + /// + /// 非法代理类型异常 + /// + /// + /// public InvalidProxiedTypeException(string message) : base(message) { } - public InvalidProxiedTypeException(string message, Exception innerException):base(message, innerException) { } + /// + /// 非法代理类型异常 + /// + /// + /// + /// + public InvalidProxiedTypeException(string message, Exception innerException) : base(message, innerException) { } } } diff --git a/src/Larva.DynamicProxy/InvocationBase.cs b/src/Larva.DynamicProxy/InvocationBase.cs new file mode 100644 index 0000000..1bb2192 --- /dev/null +++ b/src/Larva.DynamicProxy/InvocationBase.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Larva.DynamicProxy +{ + /// + /// 调用 抽象类 + /// + public abstract class InvocationBase : IInvocation + { + private Queue _interceptors; + + /// + /// 调用 抽象类 + /// + /// 拦截器 + /// 成员类型 + /// 成员名 + /// 成员操作类型 + /// 参数类型 + /// 返回类型 + /// 调用目标对象 + /// 代理对象 + /// 参数 + protected InvocationBase(IInterceptor[] interceptors, MemberTypes memberType, string memberName, MemberOperateTypes memberOperateType, Type[] argumentTypes, Type returnValueType, object invocationTarget, object proxy, object[] arguments) + { + if (interceptors != null && interceptors.Length > 0) + { + _interceptors = new Queue(interceptors); + } + MemberType = memberType; + MemberName = memberName; + MemberOperateType = memberOperateType; + ArgumentTypes = argumentTypes; + ReturnValueType = returnValueType; + InvocationTarget = invocationTarget; + Proxy = proxy; + Arguments = arguments; + } + + /// + /// 成员类型 + /// + public MemberTypes MemberType { get; private set; } + + /// + /// 成员名 + /// + public string MemberName { get; private set; } + + /// + /// 成员操作类型 + /// + public MemberOperateTypes MemberOperateType { get; private set; } + + /// + /// 参数类型 + /// + public Type[] ArgumentTypes { get; private set; } + + /// + /// 返回值类型 + /// + public Type ReturnValueType { get; private set; } + + /// + /// 调用目标对象 + /// + public object InvocationTarget { get; private set; } + + /// + /// 代理对象 + /// + public object Proxy { get; private set; } + + /// + /// 参数 + /// + public object[] Arguments { get; private set; } + + /// + /// 返回值 + /// + public object ReturnValue { get; private set; } + + /// + /// 处理 + /// + public void Proceed() + { + if (_interceptors != null && _interceptors.Count > 0) + { + var interceptor = _interceptors.Dequeue(); + interceptor.Intercept(this); + } + else + { + ReturnValue = InvokeInvocationTarget(); + } + } + + /// + /// 调用目标对象 + /// + /// + protected abstract object InvokeInvocationTarget(); + } +} \ No newline at end of file diff --git a/src/Larva.DynamicProxy/Larva.DynamicProxy.csproj b/src/Larva.DynamicProxy/Larva.DynamicProxy.csproj index c5e90b4..0583396 100644 --- a/src/Larva.DynamicProxy/Larva.DynamicProxy.csproj +++ b/src/Larva.DynamicProxy/Larva.DynamicProxy.csproj @@ -1,12 +1,33 @@ - net45;netstandard1.6;netstandard2.0 - 1.0.0 + netstandard2.0 + true + false + MIT + Jerry Bai + https://github.com/freshncp/Larva.DynamicProxy + https://github.com/freshncp/Larva.DynamicProxy.git + false + Larva.DynamicProxy + Larva.DynamicProxy + 2.0.0-beta1 + 2.0.0 + dynamic-proxy proxy aop ioc interceptor interception + dotnet 动态代理类,用于AOP + _content\package.png + true + _content + https://github.com/freshncp/Larva.DynamicProxy + - - true - - - + + + + _content\package.png + + + + + diff --git a/src/Larva.DynamicProxy/MemberOperateTypes.cs b/src/Larva.DynamicProxy/MemberOperateTypes.cs index 61b5594..cfb3773 100644 --- a/src/Larva.DynamicProxy/MemberOperateTypes.cs +++ b/src/Larva.DynamicProxy/MemberOperateTypes.cs @@ -1,11 +1,23 @@ namespace Larva.DynamicProxy { + /// + /// 成员操作类型 + /// public enum MemberOperateTypes { + /// + /// 无 + /// None = 0, + /// + /// 属性Get方法 + /// PropertyGet = 1, + /// + /// 属性Set方法 + /// PropertySet = 2 } } diff --git a/src/Larva.DynamicProxy/MethodInvocation.cs b/src/Larva.DynamicProxy/MethodInvocation.cs new file mode 100644 index 0000000..a7c5036 --- /dev/null +++ b/src/Larva.DynamicProxy/MethodInvocation.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Larva.DynamicProxy +{ + /// + /// 方法调用 + /// + public sealed class MethodInvocation : InvocationBase + { + private Queue _interceptors; + + /// + /// 方法调用 + /// + /// 拦截器 + /// 方法名 + /// 参数类型 + /// 返回值类型 + /// 调用目标对象 + /// 调用目标方法回调 + /// 代理对象 + /// 参数 + public MethodInvocation(IInterceptor[] interceptors, string methodName, Type[] argumentTypes, Type returnValueType, object invocationTarget, Func methodInvocationTargetFunc, object proxy, object[] arguments) + : base(interceptors, MemberTypes.Method, methodName, MemberOperateTypes.None, argumentTypes, returnValueType, invocationTarget, proxy, arguments) + { + if (interceptors != null && interceptors.Length > 0) + { + _interceptors = new Queue(interceptors); + } + MethodInvocationTargetFunc = methodInvocationTargetFunc; + } + + /// + /// 调用目标方法回调 + /// + public Func MethodInvocationTargetFunc { get; private set; } + + /// + /// 调用目标对象 + /// + /// + protected override object InvokeInvocationTarget() + { + return MethodInvocationTargetFunc.Invoke(Arguments); + } + } +} diff --git a/src/Larva.DynamicProxy/PropertyGetInvocation.cs b/src/Larva.DynamicProxy/PropertyGetInvocation.cs new file mode 100644 index 0000000..330db26 --- /dev/null +++ b/src/Larva.DynamicProxy/PropertyGetInvocation.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Larva.DynamicProxy +{ + /// + /// 属性的Get方法调用 + /// + public sealed class PropertyGetInvocation : InvocationBase + { + private Queue _interceptors; + + /// + /// 属性的Get方法调用 + /// + /// 拦截器 + /// 属性名 + /// 属性类型 + /// 调用目标对象 + /// 调用目标方法回调 + /// 代理对象 + public PropertyGetInvocation(IInterceptor[] interceptors, string propertyName, Type propertyType, object invocationTarget, Func methodInvocationTargetFunc, object proxy) + : base(interceptors, MemberTypes.Property, propertyName, MemberOperateTypes.PropertyGet, Type.EmptyTypes, propertyType, invocationTarget, proxy, null) + { + if (interceptors != null && interceptors.Length > 0) + { + _interceptors = new Queue(interceptors); + } + MethodInvocationTargetFunc = methodInvocationTargetFunc; + } + + /// + /// 调用目标方法回调 + /// + public Func MethodInvocationTargetFunc { get; private set; } + + /// + /// 调用目标对象 + /// + /// + protected override object InvokeInvocationTarget() + { + return MethodInvocationTargetFunc.Invoke(); + } + } +} diff --git a/src/Larva.DynamicProxy/PropertySetInvocation.cs b/src/Larva.DynamicProxy/PropertySetInvocation.cs new file mode 100644 index 0000000..a2f0590 --- /dev/null +++ b/src/Larva.DynamicProxy/PropertySetInvocation.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Larva.DynamicProxy +{ + /// + /// 属性的Set方法调用 + /// + public sealed class PropertySetInvocation : InvocationBase + { + private Queue _interceptors; + + /// + /// 属性的Set方法调用 + /// + /// 拦截器 + /// 属性名 + /// 属性类型 + /// 调用目标 + /// 调用目标方法回调 + /// 代理对象 + /// 属性值 + public PropertySetInvocation(IInterceptor[] interceptors, string propertyName, Type propertyType, object invocationTarget, Action methodInvocationTargetFunc, object proxy, object propertyValue) + : base(interceptors, MemberTypes.Property, propertyName, MemberOperateTypes.PropertySet, new Type[] { propertyType }, typeof(void), invocationTarget, proxy, new object[] { propertyValue }) + { + if (interceptors != null && interceptors.Length > 0) + { + _interceptors = new Queue(interceptors); + } + MethodInvocationTargetFunc = methodInvocationTargetFunc; + } + + /// + /// 目标方法回调 + /// + public Action MethodInvocationTargetFunc { get; private set; } + + /// + /// 调用目标对象 + /// + /// + protected override object InvokeInvocationTarget() + { + MethodInvocationTargetFunc.Invoke(Arguments[0]); + return null; + } + } +} diff --git a/src/Larva.DynamicProxy/StandardInterceptor.cs b/src/Larva.DynamicProxy/StandardInterceptor.cs index 1ab34bb..ad03a36 100644 --- a/src/Larva.DynamicProxy/StandardInterceptor.cs +++ b/src/Larva.DynamicProxy/StandardInterceptor.cs @@ -1,14 +1,20 @@ using System; -using System.Reflection; using System.Threading.Tasks; namespace Larva.DynamicProxy { + /// + /// 标准拦截器 + /// public abstract class StandardInterceptor : IInterceptor, IDisposable { + /// + /// 拦截 + /// + /// 调用 public void Intercept(IInvocation invocation) - { - if (typeof(Task).GetTypeInfo().IsAssignableFrom(invocation.MethodInvocationTarget.ReturnType)) + { + if (typeof(Task).IsAssignableFrom(invocation.ReturnValueType)) { var isFailBeforePostProceed = true; try @@ -16,27 +22,59 @@ public void Intercept(IInvocation invocation) PreProceed(invocation); invocation.Proceed(); isFailBeforePostProceed = false; - if (!invocation.ReturnValue.HasValue) + if (invocation.ReturnValue == null) { - PostProceed(invocation); + try + { + PostProceed(invocation); + } + catch { } + } + } + catch (Exception ex) + { + try + { + ExceptionThrown(invocation, ex); + } + catch { } + if (ex is AggregateException) + { + throw ex; + } + else + { + throw new AggregateException(ex); } } finally { if (isFailBeforePostProceed - || !invocation.ReturnValue.HasValue) + || invocation.ReturnValue == null) { Dispose(); } } if (!isFailBeforePostProceed - && invocation.ReturnValue.HasValue) + && invocation.ReturnValue != null) { - ((Task)invocation.ReturnValue.Value).ContinueWith((lastTask, state) => + ((Task)invocation.ReturnValue).ContinueWith((lastTask, state) => { if (lastTask.Exception == null) { - PostProceed((IInvocation)state); + try + { + PostProceed((IInvocation)state); + } + catch { } + } + else + { + try + { + ExceptionThrown((IInvocation)state, lastTask.Exception.InnerExceptions[0]); + } + catch { } } }, invocation).ContinueWith((lastTask) => { @@ -50,7 +88,20 @@ public void Intercept(IInvocation invocation) { PreProceed(invocation); invocation.Proceed(); - PostProceed(invocation); + try + { + PostProceed(invocation); + } + catch { } + } + catch (Exception ex) + { + try + { + ExceptionThrown(invocation, ex); + } + catch { } + throw new AggregateException(ex); } finally { @@ -59,13 +110,34 @@ public void Intercept(IInvocation invocation) } } + /// + /// 调用前 + /// + /// 调用 protected abstract void PreProceed(IInvocation invocation); + /// + /// 调用后 + /// + /// 调用 protected abstract void PostProceed(IInvocation invocation); - public virtual void Dispose() + /// + /// 调用时抛异常 + /// + /// 调用 + /// 异常 + protected virtual void ExceptionThrown(IInvocation invocation, Exception exception) { } + + /// + /// 释放 + /// + public virtual void Dispose() + { + + } } } diff --git a/src/Larva.DynamicProxy/WrapperObject.cs b/src/Larva.DynamicProxy/WrapperObject.cs deleted file mode 100644 index 45493c6..0000000 --- a/src/Larva.DynamicProxy/WrapperObject.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Larva.DynamicProxy -{ - public class WrapperObject - { - private object _val; - - public WrapperObject() { } - - public object Value - { - get { return _val; } - set - { - _val = value; - HasValue = true; - } - } - - public bool HasValue { get; private set; } - } -}