|
|
@ -1,16 +1,18 @@ |
|
|
// Copyright (c) .NET Foundation. All rights reserved.
|
|
|
// Copyright (c) .NET Foundation. All rights reserved.
|
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
|
|
|
|
|
|
|
|
#nullable enable |
|
|
|
|
|
|
|
|
using System; |
|
|
using System; |
|
|
using System.Collections.Generic; |
|
|
using System.Collections.Generic; |
|
|
|
|
|
using System.Diagnostics; |
|
|
using System.Linq.Expressions; |
|
|
using System.Linq.Expressions; |
|
|
using System.Reflection; |
|
|
using System.Reflection; |
|
|
|
|
|
|
|
|
namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
namespace LINGYUN.Abp.EventBus.CAP.Internal; |
|
|
|
|
|
|
|
|
|
|
|
internal class ObjectMethodExecutor |
|
|
{ |
|
|
{ |
|
|
internal class ObjectMethodExecutor |
|
|
|
|
|
{ |
|
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
|
|
|
|
private static readonly ConstructorInfo _objectMethodExecutorAwaitableConstructor = |
|
|
private static readonly ConstructorInfo _objectMethodExecutorAwaitableConstructor = |
|
|
typeof(ObjectMethodExecutorAwaitable).GetConstructor(new[] |
|
|
typeof(ObjectMethodExecutorAwaitable).GetConstructor(new[] |
|
|
{ |
|
|
{ |
|
|
@ -20,18 +22,15 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
typeof(Func<object, object>), // getResultMethod
|
|
|
typeof(Func<object, object>), // getResultMethod
|
|
|
typeof(Action<object, Action>), // onCompletedMethod
|
|
|
typeof(Action<object, Action>), // onCompletedMethod
|
|
|
typeof(Action<object, Action>) // unsafeOnCompletedMethod
|
|
|
typeof(Action<object, Action>) // unsafeOnCompletedMethod
|
|
|
}); |
|
|
})!; |
|
|
|
|
|
|
|
|
private readonly MethodExecutor _executor; |
|
|
private readonly MethodExecutor? _executor; |
|
|
private readonly MethodExecutorAsync _executorAsync; |
|
|
private readonly MethodExecutorAsync? _executorAsync; |
|
|
private readonly object[] _parameterDefaultValues; |
|
|
private readonly object?[]? _parameterDefaultValues; |
|
|
|
|
|
|
|
|
private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object[] parameterDefaultValues) |
|
|
private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object?[]? parameterDefaultValues) |
|
|
{ |
|
|
{ |
|
|
if (methodInfo == null) |
|
|
if (methodInfo == null) throw new ArgumentNullException(nameof(methodInfo)); |
|
|
{ |
|
|
|
|
|
throw new ArgumentNullException(nameof(methodInfo)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MethodInfo = methodInfo; |
|
|
MethodInfo = methodInfo; |
|
|
MethodParameters = methodInfo.GetParameters(); |
|
|
MethodParameters = methodInfo.GetParameters(); |
|
|
@ -48,10 +47,7 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
// and await it without the extra heap allocations involved in the _executorAsync code path.
|
|
|
// and await it without the extra heap allocations involved in the _executorAsync code path.
|
|
|
_executor = GetExecutor(methodInfo, targetTypeInfo); |
|
|
_executor = GetExecutor(methodInfo, targetTypeInfo); |
|
|
|
|
|
|
|
|
if (IsMethodAsync) |
|
|
if (IsMethodAsync) _executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo, coercedAwaitableInfo); |
|
|
{ |
|
|
|
|
|
_executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo, coercedAwaitableInfo); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_parameterDefaultValues = parameterDefaultValues; |
|
|
_parameterDefaultValues = parameterDefaultValues; |
|
|
} |
|
|
} |
|
|
@ -62,7 +58,7 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
|
|
|
|
|
|
public TypeInfo TargetTypeInfo { get; } |
|
|
public TypeInfo TargetTypeInfo { get; } |
|
|
|
|
|
|
|
|
public Type AsyncResultType { get; } |
|
|
public Type? AsyncResultType { get; } |
|
|
|
|
|
|
|
|
// This field is made internal set because it is set in unit tests.
|
|
|
// This field is made internal set because it is set in unit tests.
|
|
|
public Type MethodReturnType { get; internal set; } |
|
|
public Type MethodReturnType { get; internal set; } |
|
|
@ -75,12 +71,9 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo, |
|
|
public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo, |
|
|
object[] parameterDefaultValues) |
|
|
object?[] parameterDefaultValues) |
|
|
{ |
|
|
|
|
|
if (parameterDefaultValues == null) |
|
|
|
|
|
{ |
|
|
{ |
|
|
throw new ArgumentNullException(nameof(parameterDefaultValues)); |
|
|
if (parameterDefaultValues == null) throw new ArgumentNullException(nameof(parameterDefaultValues)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return new ObjectMethodExecutor(methodInfo, targetTypeInfo, parameterDefaultValues); |
|
|
return new ObjectMethodExecutor(methodInfo, targetTypeInfo, parameterDefaultValues); |
|
|
} |
|
|
} |
|
|
@ -100,8 +93,9 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
/// <param name="target">The object whose method is to be executed.</param>
|
|
|
/// <param name="target">The object whose method is to be executed.</param>
|
|
|
/// <param name="parameters">Parameters to pass to the method.</param>
|
|
|
/// <param name="parameters">Parameters to pass to the method.</param>
|
|
|
/// <returns>The method return value.</returns>
|
|
|
/// <returns>The method return value.</returns>
|
|
|
public object Execute(object target, params object[] parameters) |
|
|
public object? Execute(object target, object?[]? parameters) |
|
|
{ |
|
|
{ |
|
|
|
|
|
Debug.Assert(_executor != null, "Sync execution is not supported."); |
|
|
return _executor(target, parameters); |
|
|
return _executor(target, parameters); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -124,23 +118,19 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
/// <param name="target">The object whose method is to be executed.</param>
|
|
|
/// <param name="target">The object whose method is to be executed.</param>
|
|
|
/// <param name="parameters">Parameters to pass to the method.</param>
|
|
|
/// <param name="parameters">Parameters to pass to the method.</param>
|
|
|
/// <returns>An object that you can "await" to get the method return value.</returns>
|
|
|
/// <returns>An object that you can "await" to get the method return value.</returns>
|
|
|
public ObjectMethodExecutorAwaitable ExecuteAsync(object target, params object[] parameters) |
|
|
public ObjectMethodExecutorAwaitable ExecuteAsync(object target, object?[]? parameters) |
|
|
{ |
|
|
{ |
|
|
|
|
|
Debug.Assert(_executorAsync != null, "Async execution is not supported."); |
|
|
return _executorAsync(target, parameters); |
|
|
return _executorAsync(target, parameters); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public object GetDefaultValueForParameter(int index) |
|
|
public object? GetDefaultValueForParameter(int index) |
|
|
{ |
|
|
{ |
|
|
if (_parameterDefaultValues == null) |
|
|
if (_parameterDefaultValues == null) |
|
|
{ |
|
|
|
|
|
throw new InvalidOperationException( |
|
|
throw new InvalidOperationException( |
|
|
$"Cannot call {nameof(GetDefaultValueForParameter)}, because no parameter default values were supplied."); |
|
|
$"Cannot call {nameof(GetDefaultValueForParameter)}, because no parameter default values were supplied."); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (index < 0 || index > MethodParameters.Length - 1) |
|
|
if (index < 0 || index > MethodParameters.Length - 1) throw new ArgumentOutOfRangeException(nameof(index)); |
|
|
{ |
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(index)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return _parameterDefaultValues[index]; |
|
|
return _parameterDefaultValues[index]; |
|
|
} |
|
|
} |
|
|
@ -149,11 +139,11 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
{ |
|
|
{ |
|
|
// Parameters to executor
|
|
|
// Parameters to executor
|
|
|
var targetParameter = Expression.Parameter(typeof(object), "target"); |
|
|
var targetParameter = Expression.Parameter(typeof(object), "target"); |
|
|
var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); |
|
|
var parametersParameter = Expression.Parameter(typeof(object?[]), "parameters"); |
|
|
|
|
|
|
|
|
// Build parameter list
|
|
|
// Build parameter list
|
|
|
var parameters = new List<Expression>(); |
|
|
|
|
|
var paramInfos = methodInfo.GetParameters(); |
|
|
var paramInfos = methodInfo.GetParameters(); |
|
|
|
|
|
var parameters = new List<Expression>(paramInfos.Length); |
|
|
for (var i = 0; i < paramInfos.Length; i++) |
|
|
for (var i = 0; i < paramInfos.Length; i++) |
|
|
{ |
|
|
{ |
|
|
var paramInfo = paramInfos[i]; |
|
|
var paramInfo = paramInfos[i]; |
|
|
@ -187,7 +177,7 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
|
|
|
|
|
|
private static MethodExecutor WrapVoidMethod(VoidMethodExecutor executor) |
|
|
private static MethodExecutor WrapVoidMethod(VoidMethodExecutor executor) |
|
|
{ |
|
|
{ |
|
|
return delegate (object target, object[] parameters) |
|
|
return delegate (object target, object?[]? parameters) |
|
|
{ |
|
|
{ |
|
|
executor(target, parameters); |
|
|
executor(target, parameters); |
|
|
return null; |
|
|
return null; |
|
|
@ -204,8 +194,8 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); |
|
|
var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); |
|
|
|
|
|
|
|
|
// Build parameter list
|
|
|
// Build parameter list
|
|
|
var parameters = new List<Expression>(); |
|
|
|
|
|
var paramInfos = methodInfo.GetParameters(); |
|
|
var paramInfos = methodInfo.GetParameters(); |
|
|
|
|
|
var parameters = new List<Expression>(paramInfos.Length); |
|
|
for (var i = 0; i < paramInfos.Length; i++) |
|
|
for (var i = 0; i < paramInfos.Length; i++) |
|
|
{ |
|
|
{ |
|
|
var paramInfo = paramInfos[i]; |
|
|
var paramInfo = paramInfos[i]; |
|
|
@ -250,7 +240,11 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
var getResultParam = Expression.Parameter(typeof(object), "awaiter"); |
|
|
var getResultParam = Expression.Parameter(typeof(object), "awaiter"); |
|
|
Func<object, object> getResultFunc; |
|
|
Func<object, object> getResultFunc; |
|
|
if (awaitableInfo.ResultType == typeof(void)) |
|
|
if (awaitableInfo.ResultType == typeof(void)) |
|
|
{ |
|
|
// var getResultFunc = (object awaiter) =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// ((CustomAwaiterType)awaiter).GetResult(); // We need to invoke this to surface any exceptions
|
|
|
|
|
|
// return (object)null;
|
|
|
|
|
|
// };
|
|
|
getResultFunc = Expression.Lambda<Func<object, object>>( |
|
|
getResultFunc = Expression.Lambda<Func<object, object>>( |
|
|
Expression.Block( |
|
|
Expression.Block( |
|
|
Expression.Call( |
|
|
Expression.Call( |
|
|
@ -259,9 +253,9 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
Expression.Constant(null) |
|
|
Expression.Constant(null) |
|
|
), |
|
|
), |
|
|
getResultParam).Compile(); |
|
|
getResultParam).Compile(); |
|
|
} |
|
|
|
|
|
else |
|
|
else |
|
|
{ |
|
|
// var getResultFunc = (object awaiter) =>
|
|
|
|
|
|
// (object)((CustomAwaiterType)awaiter).GetResult();
|
|
|
getResultFunc = Expression.Lambda<Func<object, object>>( |
|
|
getResultFunc = Expression.Lambda<Func<object, object>>( |
|
|
Expression.Convert( |
|
|
Expression.Convert( |
|
|
Expression.Call( |
|
|
Expression.Call( |
|
|
@ -269,7 +263,6 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
awaitableInfo.AwaiterGetResultMethod), |
|
|
awaitableInfo.AwaiterGetResultMethod), |
|
|
typeof(object)), |
|
|
typeof(object)), |
|
|
getResultParam).Compile(); |
|
|
getResultParam).Compile(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// var onCompletedFunc = (object awaiter, Action continuation) => {
|
|
|
// var onCompletedFunc = (object awaiter, Action continuation) => {
|
|
|
// ((CustomAwaiterType)awaiter).OnCompleted(continuation);
|
|
|
// ((CustomAwaiterType)awaiter).OnCompleted(continuation);
|
|
|
@ -284,7 +277,7 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
onCompletedParam1, |
|
|
onCompletedParam1, |
|
|
onCompletedParam2).Compile(); |
|
|
onCompletedParam2).Compile(); |
|
|
|
|
|
|
|
|
Action<object, Action> unsafeOnCompletedFunc = null; |
|
|
Action<object, Action>? unsafeOnCompletedFunc = null; |
|
|
if (awaitableInfo.AwaiterUnsafeOnCompletedMethod != null) |
|
|
if (awaitableInfo.AwaiterUnsafeOnCompletedMethod != null) |
|
|
{ |
|
|
{ |
|
|
// var unsafeOnCompletedFunc = (object awaiter, Action continuation) => {
|
|
|
// var unsafeOnCompletedFunc = (object awaiter, Action continuation) => {
|
|
|
@ -328,10 +321,9 @@ namespace LINGYUN.Abp.EventBus.CAP.Internal |
|
|
return lambda.Compile(); |
|
|
return lambda.Compile(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private delegate ObjectMethodExecutorAwaitable MethodExecutorAsync(object target, params object[] parameters); |
|
|
private delegate ObjectMethodExecutorAwaitable MethodExecutorAsync(object target, object?[]? parameters); |
|
|
|
|
|
|
|
|
private delegate object MethodExecutor(object target, params object[] parameters); |
|
|
private delegate object? MethodExecutor(object target, object?[]? parameters); |
|
|
|
|
|
|
|
|
private delegate void VoidMethodExecutor(object target, object[] parameters); |
|
|
private delegate void VoidMethodExecutor(object target, object?[]? parameters); |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|