/// <summary> /// Gets what 'kind' of return the method provides. /// </summary> private static returnKindEnum GetReturnType(MethodInfo m) { returnKindEnum rt = 0; if (m.ReturnType == typeof(void)) { rt = returnKindEnum.voidType; } else if (m.ReturnType == typeof(Task) && m.ReturnType.IsConstructedGenericType == false) { rt = returnKindEnum.TaskType; } else if (IsTaskReturnType(m.ReturnType)) { if (IsAsyncEnumerableType(GetInnerReturnType(m.ReturnType))) { rt = returnKindEnum.TaskAsyncEnumReturnType; } else if (IsChannelReaderType(GetInnerReturnType(m.ReturnType))) { rt = returnKindEnum.TaskChannelReaderReturnType; } else { rt = returnKindEnum.TaskReturnType; } } else if (IsAsyncEnumerableType(m.ReturnType)) { rt = returnKindEnum.AsyncEnumReturnType; } else if (IsChannelReaderType(m.ReturnType)) { rt = returnKindEnum.ChannelReaderReturnType; } else { rt = returnKindEnum.ReturnType; } return(rt); }
/// <summary> /// Determines which method to call for the invocation /// </summary> /// <returns>The selected Method on the <see cref="HubConnection"/> to use.</returns> private static MethodInfo CreateHubMethod(bool useInvokeForAll, MethodInfo method, Type retType, returnKindEnum rett) { switch (rett) { case returnKindEnum.voidType: case returnKindEnum.TaskType: //Firing order: // AlwaysInvoke? ->Invoke // AlwaySend? ->Send // invokeForAll true->Invoke // false->Send return(((useInvokeForAll && method.GetCustomAttributes() .Any(a => a is AlwaysSendAttribute) == false) || method.GetCustomAttributes() .Any(a => a is AlwaysInvokeAttribute)) ? typeof(HubExtender).GetMethod( nameof(HubExtender.PerformInvokeCoreAsyncNoReturn)) : typeof(HubExtender).GetMethod( nameof(HubExtender.PerformSendCoreAsync))); case returnKindEnum.AsyncEnumReturnType: //If getting back an async enum, we need to stream. return(typeof(HubExtender) .GetMethod( nameof(HubExtender.PerformStreamCoreAsync)) ?.MakeGenericMethod(new[] { retType })); case returnKindEnum.TaskAsyncEnumReturnType: //Edge case: The API for once isn't returning a Task //So PerformStreamCoreAsyncTask wraps in a task for us. return(typeof(HubExtender) .GetMethod( nameof(HubExtender.PerformStreamCoreAsyncTask)) ?.MakeGenericMethod(new[] { retType })); case returnKindEnum.TaskChannelReaderReturnType: case returnKindEnum.ChannelReaderReturnType: //ChannelReader is given back as Task<ChannelReader<T>> //So we follow GetAwaiter().GetResult() semantics here. return(typeof(HubExtender) .GetMethod( nameof(HubExtender.PerformChannelReadStreamCoreAsync)) ?.MakeGenericMethod(new[] { retType })); case returnKindEnum.TaskReturnType: case returnKindEnum.ReturnType: default: //Logically speaking this is default regardless. return(typeof(HubExtender) .GetMethod( nameof(HubExtender.PerformInvokeCoreAsyncReturn)) ?.MakeGenericMethod(new[] { retType })); } }