本文摘自:https://bbs.csdn.net/topics/300182899 
 
JS在调用的时候会传递几个入参进来, 比如 类名 函数名 参数 
 
首先,根据类名,可以找到 需要调用的类型 Type type = Activator.CreateInstance 
 
然后,根据函数名称, 可以找到 需要调用的MethodInfo. 
MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); 
 
接着,就可以获取到参数列表了。就可以调用了。 
ParameterInfo[] paramInfos = methodInfo.GetParameters(); 
var paramObjs = new object[paramInfos .Length]; 
// 填充参数 
methodInfo.Invoke(sink, paramObjs);  
 
=================== 
我的问题来了, 
 
我的参数不是简单类型参数, 而是一个JSON数据对象。 
 
比如某函数的参数为QueryCustomerReq,定义为: 
 
public class QueryCustomerReq 
{ 
    public string PhoneNumber { get; set; } 
    public string PostalCode { get; set; } 
} 
 
 
那么在调用此函数传递这个参数的时候,使用的JSON对象是: 
JavaScript code 
var oParam = {}; 
oParam.PhoneNumber = "XXXXXXXXX"; 
oParam.PostalCode = "YYYYYYYY"; 
 
 
一般情况下,使用JavaScriptSerializer类来反序列化JSON.如 
JavaScriptSerializer serializer = new JavaScriptSerializer(); 
serializer.Deserialize<QueryCustomerReq>("{PhoneNumber:'sss', PostalCode :'YYY'}"); 
 
这样是可以的!  
但是!这里模板参数不能在编译期确定,因为调用哪个函数是脚本决定的。 也就是说, 必须根据ParameterInfo.ParameterType来决定怎么反序列化这个JSON对象。 
 
到底如何做才能解决这个问题呢? 
============= 
方式1: 一个很大的switch, MY GOD, 这种方式杀了我吧, 我不可能维护这个switch的。 
方式2: 从JavaScriptConverter派生自己的类,然后JavaScriptSerializer.RegisterConverters 注册这个类,然后使用JavaScriptSerializer.DeserializeObject来转换。 
      这样也是不可能的, 因为JavaScriptConverter的派生类仍然需要调用基类的ConvertToType<T>来实现转换。 我的参数类型是无限的。 
方式3: 使用DynamicMethod, 我觉得这种是唯一可行的方式。 生成一个DynamicMethod, 这个DynamicMethod里面完成类型转换后再调用目标函数, 但是好复杂,不知道写, 忘高人指点 
 
 
作者总结: 
public class RemoteInvoke : HttpHandlerBase 
{ 
    private delegate object DynamicMethodDelegate(string json, RemoteSink remoteSink); 
  
  
    protected override object ProcessRequest() 
    { 
        base.ValidateCredential(); 
  
        string methodName = HttpContext.Current.Request.Form["MethodName"]; 
        string paramter = HttpContext.Current.Request.Form["Parameter"]; 
  
        if (string.IsNullOrEmpty(methodName) || 
            string.IsNullOrEmpty(paramter) ) 
        { 
            throw new ArgumentException("The input parameters are required."); 
        } 
  
        RemoteSink sink = new RemoteSink(); 
        Type type = sink.GetType(); 
  
        MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); 
        if (methodInfo == null) 
            throw new ArgumentException("Error, cannot find the specific method by name."); 
  
        ParameterInfo[] paramInfos = methodInfo.GetParameters(); 
        if (paramInfos == null || 
            paramInfos.Length != 1 ) 
        { 
            throw new ArgumentException("Error, method requires more than one paramter."); 
        } 
         
        
        Type[] newMethodArgs = { typeof(string), type }; 
        DynamicMethod newMethod = new DynamicMethod( "dynamicMethod" 
            , typeof(object) 
            , newMethodArgs 
            , type.Module 
            ); 
        ILGenerator generator = newMethod.GetILGenerator(); 
        generator.Emit(OpCodes.Ldarg_1); 
        generator.Emit(OpCodes.Newobj, typeof(JavaScriptSerializer).GetConstructor(Type.EmptyTypes)); 
        generator.Emit(OpCodes.Ldarg_0); 
        generator.Emit(OpCodes.Call, typeof(JavaScriptSerializer).GetMethod("Deserialize", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(paramInfos[0].ParameterType)); 
        generator.Emit(OpCodes.Callvirt, methodInfo); 
        generator.Emit(OpCodes.Ret); 
        DynamicMethodDelegate dynamicMethodDel  
            = (DynamicMethodDelegate)newMethod.CreateDelegate(typeof(DynamicMethodDelegate)); 
  
        return dynamicMethodDel(paramter, sink); 
    } 
} |