Port ObjectMethodExecutor race fix

This commit is contained in:
BrennanConroy 2017-03-27 09:19:08 -07:00
parent 6130003193
commit 09667e86ab
1 changed files with 41 additions and 45 deletions

View File

@ -14,9 +14,9 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{ {
internal class ObjectMethodExecutor internal class ObjectMethodExecutor
{ {
private object[] _parameterDefaultValues; private readonly object[] _parameterDefaultValues;
private ActionExecutorAsync _executorAsync; private readonly ActionExecutorAsync _executorAsync;
private ActionExecutor _executor; private readonly ActionExecutor _executor;
private static readonly MethodInfo _convertOfTMethod = private static readonly MethodInfo _convertOfTMethod =
typeof(ObjectMethodExecutor).GetRuntimeMethods().Single(methodInfo => methodInfo.Name == nameof(ObjectMethodExecutor.Convert)); typeof(ObjectMethodExecutor).GetRuntimeMethods().Single(methodInfo => methodInfo.Name == nameof(ObjectMethodExecutor.Convert));
@ -27,12 +27,26 @@ namespace Microsoft.AspNetCore.SignalR.Internal
{ {
throw new ArgumentNullException(nameof(methodInfo)); throw new ArgumentNullException(nameof(methodInfo));
} }
MethodInfo = methodInfo; MethodInfo = methodInfo;
TargetTypeInfo = targetTypeInfo; TargetTypeInfo = targetTypeInfo;
ActionParameters = methodInfo.GetParameters(); ActionParameters = methodInfo.GetParameters();
MethodReturnType = methodInfo.ReturnType; MethodReturnType = methodInfo.ReturnType;
IsMethodAsync = typeof(Task).IsAssignableFrom(MethodReturnType); IsMethodAsync = typeof(Task).IsAssignableFrom(MethodReturnType);
TaskGenericType = IsMethodAsync ? GetTaskInnerTypeOrNull(MethodReturnType) : null; TaskGenericType = IsMethodAsync ? GetTaskInnerTypeOrNull(MethodReturnType) : null;
if (IsMethodAsync && TaskGenericType != null)
{
// For backwards compatibility we're creating a sync-executor for an async method.
_executor = GetExecutor(methodInfo, targetTypeInfo);
_executorAsync = GetExecutorAsync(TaskGenericType, methodInfo, targetTypeInfo);
}
else
{
_executor = GetExecutor(methodInfo, targetTypeInfo);
}
_parameterDefaultValues = GetParameterDefaultValues(ActionParameters);
} }
private delegate Task<object> ActionExecutorAsync(object target, object[] parameters); private delegate Task<object> ActionExecutorAsync(object target, object[] parameters);
@ -54,29 +68,15 @@ namespace Microsoft.AspNetCore.SignalR.Internal
public bool IsMethodAsync { get; } public bool IsMethodAsync { get; }
private ActionExecutorAsync TaskOfTActionExecutorAsync
{
get
{
if (_executorAsync == null)
{
_executorAsync = GetExecutorAsync(TaskGenericType, MethodInfo, TargetTypeInfo);
}
return _executorAsync;
}
}
public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo)
{ {
var executor = new ObjectMethodExecutor(methodInfo, targetTypeInfo); var executor = new ObjectMethodExecutor(methodInfo, targetTypeInfo);
executor._executor = GetExecutor(methodInfo, targetTypeInfo);
return executor; return executor;
} }
public Task<object> ExecuteAsync(object target, object[] parameters) public Task<object> ExecuteAsync(object target, object[] parameters)
{ {
return TaskOfTActionExecutorAsync(target, parameters); return _executorAsync(target, parameters);
} }
public object Execute(object target, object[] parameters) public object Execute(object target, object[] parameters)
@ -91,8 +91,6 @@ namespace Microsoft.AspNetCore.SignalR.Internal
throw new ArgumentOutOfRangeException(nameof(index)); throw new ArgumentOutOfRangeException(nameof(index));
} }
EnsureParameterDefaultValues();
return _parameterDefaultValues[index]; return _parameterDefaultValues[index];
} }
@ -221,42 +219,40 @@ namespace Microsoft.AspNetCore.SignalR.Internal
return CastToObject<T>(task); return CastToObject<T>(task);
} }
private void EnsureParameterDefaultValues() private static object[] GetParameterDefaultValues(ParameterInfo[] parameters)
{ {
if (_parameterDefaultValues == null) var values = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{ {
var count = ActionParameters.Length; var parameterInfo = parameters[i];
_parameterDefaultValues = new object[count]; object defaultValue;
for (var i = 0; i < count; i++) if (parameterInfo.HasDefaultValue)
{ {
var parameterInfo = ActionParameters[i]; defaultValue = parameterInfo.DefaultValue;
object defaultValue; }
else
if (parameterInfo.HasDefaultValue) {
var defaultValueAttribute = parameterInfo
.GetCustomAttribute<DefaultValueAttribute>(inherit: false);
if (defaultValueAttribute?.Value == null)
{ {
defaultValue = parameterInfo.DefaultValue; defaultValue = parameterInfo.ParameterType.GetTypeInfo().IsValueType
? Activator.CreateInstance(parameterInfo.ParameterType)
: null;
} }
else else
{ {
var defaultValueAttribute = parameterInfo defaultValue = defaultValueAttribute.Value;
.GetCustomAttribute<DefaultValueAttribute>(inherit: false);
if (defaultValueAttribute?.Value == null)
{
defaultValue = parameterInfo.ParameterType.GetTypeInfo().IsValueType
? Activator.CreateInstance(parameterInfo.ParameterType)
: null;
}
else
{
defaultValue = defaultValueAttribute.Value;
}
} }
_parameterDefaultValues[i] = defaultValue;
} }
values[i] = defaultValue;
} }
return values;
} }
} }
} }