private void InitMethodsFromType(Type type, bool isAttributedMethodsOnly)
        {
            foreach (var methodInfo in type.GetMethods())
            {
                RpcMethodAttribute methodAttr = GetMethodAttribute(methodInfo);
                if (methodAttr != null || !isAttributedMethodsOnly)
                {
                    RpcMethodDescriptor method = new RpcMethodDescriptor(methodInfo, methodAttr, name);
                    if (methods.ContainsKey(method.Name))
                    {
                        methods[method.Name].Merge(method);
                    }
                    else
                    {
                        methods.Add(method.Name, method);
                    }
                }
            }

            //for classes checking the public methods is enough, but for an interface we must check the other
            //interfaces implemented too
            if (type.IsInterface)
            {
                foreach (var interfaceType in type.GetInterfaces())
                {
                    InitMethodsFromType(interfaceType, isAttributedMethodsOnly);
                }
            }
        }
        public RpcMethodDescriptor(MethodInfo methodInfo, RpcMethodAttribute attr, string serviceName)
        {
            this.serviceName = serviceName;

            Type[] methodParamTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();

            if (methodInfo.Name.StartsWith("Begin") && methodParamTypes.Length >= 2 &&
                methodInfo.ReturnType == typeof(IAsyncResult) &&
                methodParamTypes[methodParamTypes.Length - 2] == typeof(AsyncCallback) &&
                methodParamTypes[methodParamTypes.Length - 1] == typeof(object))
            {
                asyncBeginMethodInfo = methodInfo;
                parameterTypes       = methodParamTypes.Take(methodParamTypes.Length - 2).ToArray();
                if (attr != null && attr.Name != null)
                {
                    name = attr.Name;
                }
                else
                {
                    name = methodInfo.Name.Substring(5);
                }
            }
            else if (methodInfo.Name.StartsWith("End") && methodParamTypes.Length == 1 &&
                     methodParamTypes[0] == typeof(IAsyncResult))
            {
                asyncEndMethodInfo = methodInfo;
                returnType         = methodInfo.ReturnType;
                if (attr != null && attr.Name != null)
                {
                    name = attr.Name;
                }
                else
                {
                    name = methodInfo.Name.Substring(3);
                }
            }
            else
            {
                syncMethodInfo = methodInfo;
                parameterTypes = methodParamTypes;
                returnType     = methodInfo.ReturnType;
                if (attr != null && attr.Name != null)
                {
                    name = attr.Name;
                }
                else
                {
                    name = methodInfo.Name;
                }
            }

            //verify parameters
            if (parameterTypes != null)
            {
                foreach (Type paramType in parameterTypes)
                {
                    if (!ParameterConverter.IsSupportedType(paramType))
                    {
                        throw new ArgumentException(
                                  String.Format(
                                      "Parameter of type '{0}' on method '{1}' in service '{2}' is not a supported type.",
                                      paramType, methodInfo.Name, serviceName));
                    }
                }
            }

            //verify return type
            if (returnType != null && returnType != typeof(void))
            {
                if (!ParameterConverter.IsSupportedType(returnType))
                {
                    throw new ArgumentException(
                              String.Format("Return type '{0}' of method '{1}' in service '{2}' is not a supported type",
                                            returnType, name, serviceName));
                }
            }
        }
        public RpcMethodDescriptor(MethodInfo methodInfo, RpcMethodAttribute attr, string serviceName)
        {
            this.serviceName = serviceName;

            Type[] methodParamTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();

            if (methodInfo.Name.StartsWith("Begin") && methodParamTypes.Length >= 2
                && methodInfo.ReturnType == typeof(IAsyncResult)
                && methodParamTypes[methodParamTypes.Length - 2] == typeof(AsyncCallback)
                && methodParamTypes[methodParamTypes.Length - 1] == typeof(object))
            {
                asyncBeginMethodInfo = methodInfo;
                parameterTypes = methodParamTypes.Take(methodParamTypes.Length-2).ToArray();
                if (attr != null && attr.Name != null)
                    name = attr.Name;
                else
                    name = methodInfo.Name.Substring(5);
            }
            else if (methodInfo.Name.StartsWith("End") && methodParamTypes.Length == 1
                && methodParamTypes[0] == typeof(IAsyncResult))
            {
                asyncEndMethodInfo = methodInfo;
                returnType = methodInfo.ReturnType;
                if (attr != null && attr.Name != null)
                    name = attr.Name;
                else
                    name = methodInfo.Name.Substring(3);
            }
            else
            {
                syncMethodInfo = methodInfo;
                parameterTypes = methodParamTypes;
                returnType = methodInfo.ReturnType;
                if (attr != null && attr.Name != null)
                    name = attr.Name;
                else
                    name = methodInfo.Name;
            }

            //verify parameters
            if (parameterTypes != null)
            {
                foreach (Type paramType in parameterTypes)
                {
                    if (!ParameterConverter.IsSupportedType(paramType))
                        throw new ArgumentException(
                            String.Format(
                                "Parameter of type '{0}' on method '{1}' in service '{2}' is not a supported type.",
                                paramType, methodInfo.Name, serviceName));
                }
            }

            //verify return type
            if (returnType != null && returnType != typeof(void))
            {
                if (!ParameterConverter.IsSupportedType(returnType))
                    throw new ArgumentException(
                        String.Format("Return type '{0}' of method '{1}' in service '{2}' is not a supported type",
                            returnType, name, serviceName));
            }
        }