问个有点难度的问题, 关于反射动态调用方法

CodeProject-Jerry 2009-04-08 05:16:26
我正在实现脚本引擎, 在JS中调用C#的类中的方法

那么,首先,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对象是:

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里面完成类型转换后再调用目标函数, 但是好复杂,不知道写, 忘高人指点
...全文
485 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
ws_hgo 2009-04-08
  • 打赏
  • 举报
回复
学习
wuyq11 2009-04-08
  • 打赏
  • 举报
回复
不错,顶
cppfaq 2009-04-08
  • 打赏
  • 举报
回复
有重载怎么办?

个人觉得还是在JSON里面带上类型信息比较好
我姓区不姓区 2009-04-08
  • 打赏
  • 举报
回复
好东西,我建议楼主将这个贴子转到C#区去
CodeProject-Jerry 2009-04-08
  • 打赏
  • 举报
回复
研究了2个小时后,终于整出来了。 这个帖子留作散分吧


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);
}
}
CodeProject-Jerry 2009-04-08
  • 打赏
  • 举报
回复
Type type = Activator.CreateInstance
这句笔误, 不过意思就是根据名称获取到类型

17,748

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧