public MethodInvokeResultCommsMessage(IMethodInvokeCommsMessage invokeMessage, object returnValue) : base(CommsMessageType.MethodInvokeResult) { _invokeMessage = invokeMessage; _returnValue = returnValue; }
private ICommsMessage _handleMethodInvoke(object target, IMethodInvokeCommsMessage msg) { if (target == null) throw Ex.ArgNull(() => target); if (msg == null) throw Ex.ArgNull(() => msg); if (msg.Type != CommsMessageType.MethodInvoke) throw Ex.Arg(() => msg, "The message should be a method invoke comms message"); try { if (_dictMethodInvokeCache.ContainsKey(msg.MethodName)) { return new MethodInvokeResultCommsMessage(msg, _dictMethodInvokeCache[msg.MethodName].DynamicInvoke(msg.InvokeArgs)); } else { var typ = target.GetType(); MethodInfo chosenMethod = typ.GetMethod(msg.MethodName); if (chosenMethod == null) { // The method couldn't be found, it could be because it's implemented explicitly // try to find an explicit hit via the interfaces var interfaces = typ.GetInterfaces(); if (interfaces != null && interfaces.Length > 0) { var methNames = interfaces.Where(i => i.GetMethod(msg.MethodName) != null) .Select(i => new { explicitName = i.Name + "." + msg.MethodName, iface = i, meth = i.GetMethod(msg.MethodName), }).ToArray(); if (methNames == null || methNames.Length == 0) { throw new InvalidOperationException("Method not present on target type " + "and none of the implemented interfaces held a method for explicit resolution"); } else { // There's a slight possibility of method names matching // for more than one explicit implementation // it's less likely they match on argument signatures, so // identify the method that has the right signature List<MethodInfo> lstFoundMethods = new List<MethodInfo>(); foreach (var mn in methNames) { var paras = mn.meth.GetParameters(); if (paras == null || paras.Length == 0 && (msg.InvokeArgs == null || msg.InvokeArgs.Length == 0)) { // No arguments supplied or expected, this is a candidate lstFoundMethods.Add(mn.meth); } else { // There are some arguments if (paras.Length == msg.InvokeArgs.Length) { // Only care if the same number of arguments count // Check each argument has the same type bool isMatch = true; for (int i = 0; i < paras.Length; i++) { if (!paras[i].ParameterType.IsAssignableFrom(msg.InvokeArgs[i].GetType())) { isMatch = false; break; } } if (isMatch) { lstFoundMethods.Add(mn.meth); } } } } if (lstFoundMethods.Count == 0) { throw new InvalidOperationException("Method not present on target type " + "and no interfaces had suitable methods for selection"); } else if (lstFoundMethods.Count > 1) { throw new InvalidOperationException("Method not present on target type " + "and multiple interfaces had suitable methods for selection, choice was ambiguous"); } else { // We have exactly one suitable method at the end of it all chosenMethod = lstFoundMethods[0]; } } } else { throw new InvalidOperationException("Method not present on target type " + "and no interfaces were available for explicit implementation resolution"); } } var call = Expression.Call(Expression.Constant(target), chosenMethod, chosenMethod .GetParameters() .Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray()); var lamb = Expression.Lambda(call, call.Arguments.Cast<ParameterExpression>().ToArray()).Compile(); _dictMethodInvokeCache[msg.MethodName] = lamb; return new MethodInvokeResultCommsMessage(msg, lamb.DynamicInvoke(msg.InvokeArgs)); } } catch (Exception ex) { throw new ApplicationException("Failed to process method invoke message", ex); } }