コード例 #1
0
 public MethodInvokeResultCommsMessage(IMethodInvokeCommsMessage invokeMessage,
     object returnValue)
     : base(CommsMessageType.MethodInvokeResult)
 {
     _invokeMessage = invokeMessage;
     _returnValue = returnValue;
 }
コード例 #2
0
        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);
            }
        }