private void BuildAnnotatedMessageHandlers() { // create a handler for every method which has MessageHandlerAttribute var methods = _type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var method in methods) { var attr = method.GetCustomAttribute <MessageHandlerAttribute>(); if (attr == null) { continue; } var messageType = attr.Type ?? method.GetParameters()[0].ParameterType; var isAsyncMethod = (method.ReturnType.Name.StartsWith("Task")); var filterChain = _filterHandlerBuilder.Build(method, FilterChainKind.Message); var isSyncHandler = isAsyncMethod == false && filterChain.AsyncFilterExists == false; var isReentrant = isSyncHandler == false && HandlerBuilderHelpers.IsReentrantMethod(method); if (isAsyncMethod == false && method.GetCustomAttribute <AsyncStateMachineAttribute>() != null) { throw new InvalidOperationException($"Async void handler is not supported. ({_type.FullName}.{method.Name})"); } AddHandler(method, messageType, filterChain, isSyncHandler, isReentrant); } }
private void BuildRegularInterfaceHandlers() { foreach (var ifs in _type.GetInterfaces()) { if (ifs.GetInterfaces().All(t => t != typeof(IInterfacedObserver) && t != typeof(IInterfacedObserverSync))) { continue; } var primaryInterface = ifs; var alternativeInterfaceAttribute = ifs.GetCustomAttribute <AlternativeInterfaceAttribute>(); if (alternativeInterfaceAttribute != null) { primaryInterface = alternativeInterfaceAttribute.Type.IsGenericType ? alternativeInterfaceAttribute.Type.MakeGenericType(ifs.GetGenericArguments()) : alternativeInterfaceAttribute.Type; } var interfaceMap = _type.GetInterfaceMap(ifs); var methodItems = interfaceMap.InterfaceMethods.Zip(interfaceMap.TargetMethods, Tuple.Create) .OrderBy(p => p.Item1, new MethodInfoComparer()) .ToArray(); var payloadTypeTable = GetInterfacePayloadTypeTable(primaryInterface); // build a decorated handler for each method. for (var i = 0; i < methodItems.Length; i++) { var targetMethod = methodItems[i].Item2; var invokePayloadType = payloadTypeTable[i]; var filterChain = _filterHandlerBuilder.Build(targetMethod, FilterChainKind.Notification); var isSyncHandler = alternativeInterfaceAttribute == null && filterChain.AsyncFilterExists == false; var isReentrant = isSyncHandler == false && HandlerBuilderHelpers.IsReentrantMethod(targetMethod); AddHandler(ifs, targetMethod, invokePayloadType, filterChain, isSyncHandler, isReentrant); } } }
private void BuildExtendedInterfaceHandlers() { var targetMethods = _type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) .Where(m => m.GetCustomAttribute <ExtendedHandlerAttribute>() != null) .Select(m => Tuple.Create(m, m.GetCustomAttribute <ExtendedHandlerAttribute>())) .ToList(); var extendedInterfaces = _type.GetInterfaces() .Where(t => t.FullName.StartsWith("Akka.Interfaced.IExtendedInterface")) .SelectMany(t => t.GenericTypeArguments) .Where(t => t.GetInterfaces().Any(i => i == typeof(IInterfacedObserver))); // includes base interfaces var extendedAllInterfaces = extendedInterfaces .Concat(extendedInterfaces.SelectMany(t => t.GetInterfaces().Where(u => u != typeof(IInterfacedObserver)))) .Distinct().ToArray(); foreach (var ifs in extendedAllInterfaces) { var payloadTypeTable = GetInterfacePayloadTypeTable(ifs); var interfaceMethods = ifs.GetMethods().OrderBy(m => m, new MethodInfoComparer()).ToArray(); // build a decorated handler for each method. for (var i = 0; i < interfaceMethods.Length; i++) { var interfaceMethod = interfaceMethods[i]; var invokePayloadType = payloadTypeTable[i]; var name = interfaceMethod.Name; var parameters = interfaceMethod.GetParameters(); // find a method which can handle this invoke payload MethodInfo targetMethod = null; foreach (var method in targetMethods) { if (method.Item2.Type != null || method.Item2.Method != null) { // check tagged method if (method.Item2.Type != null && method.Item2.Type != ifs) { continue; } if (method.Item2.Method != null && method.Item2.Method != name) { continue; } } else if (method.Item1.Name != name) { // check method continue; } if (HandlerBuilderHelpers.AreParameterTypesEqual(method.Item1.GetParameters(), parameters)) { if (targetMethod != null) { throw new InvalidOperationException( $"Ambiguous handlers for {ifs.FullName}.{interfaceMethod.Name} method.\n" + $" {targetMethod.Name}\n {method.Item1.Name}\n"); } targetMethod = method.Item1; } } if (targetMethod == null) { throw new InvalidOperationException( $"Cannot find handler for {ifs.FullName}.{interfaceMethod.Name}"); } targetMethods.RemoveAll(x => x.Item1 == targetMethod); // build handler var isAsyncMethod = targetMethod.ReturnType.Name.StartsWith("Task"); var filterChain = _filterHandlerBuilder.Build(targetMethod, FilterChainKind.Notification); var isSyncHandler = isAsyncMethod == false && filterChain.AsyncFilterExists == false; var isReentrant = isSyncHandler == false && HandlerBuilderHelpers.IsReentrantMethod(targetMethod); if (isAsyncMethod == false && targetMethod.GetCustomAttribute <AsyncStateMachineAttribute>() != null) { throw new InvalidOperationException($"Async void handler is not supported. ({_type.FullName}.{targetMethod.Name})"); } AddHandler(ifs, targetMethod, invokePayloadType, filterChain, isSyncHandler, isReentrant); } } }