通过反射(Reflection)实现对ref和out参数在 Portal-Builder 开源门户系统中的调用
2012-03-20 21:45 mleader1 阅读(1623) 评论(0) 编辑 收藏 举报最近做的Portal-Builder 开源门户系统里面用到了相当多的反射(不知道这样叫中文对不对,英文是Reflection),很多人对ref和out参数如何传递使用不太清楚,在这里我来给大家介绍一下:
其实实现我们大部分时间是采用 MethodInfo.Invoke() 来实现,所以细节就在怎么使用 Type.GetMethod()这个方法了
解密:
Type 里面有 MakeByRefType()和 MakeArrayType() 两个方法, 其中 ref和out 都可以通过MakeByRefType 来实现, 因为 ref和out 其实都可以当作是把方法外的参数当作一个 object对象传入,从而实现带值返回。 MakeArratType简单介绍就是声明传入的数据为数组,如是而已。
下面附带一下 Portal-Builder 开源门户里面的使用ActionRunner来调用XML实现类方法调用的例子:
PortalBuilderActions.xml 代码样例
<?xml version="1.0" encoding="utf-8" ?>
<PortalBuilderActions>
<!--每个应用下面应该都有一个PortalBuilderActions.xml 在系统启动时会全部读入系统Cache用于高速运算-->
<!--
<Applicatoin>
Name: 当前操作集所属应用程序的名称
AppKey: 当前操作及所属应用程序的唯一码
-->
<Application Name="PBFramework" AppKey="EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F">
<!--
<ActionGroup> 应用开发者对自己应用程序内操作的归类,方便进行管理
-->
<ActionGroup Name="会员操作">
<!--
<Actions> 操作集
<Action> :单个操作的定义
Name: 单个操作的名称定义, 注意:整个应用程序下,操作名称定义必须唯一
<Flows> 定义操作中的操作流:操流可以为多项内容,即该项操作涉及到多个代码方面的执行,Flow分为两种
<ManagerFlow> 直接对接Portal-Builder应用代码的操作流,通过定义 ClassName、 AssemblyName、 MethodName 用反射方法来实现方法的调用
<ActionFlow> 调用另外一个操作定义,在执行完毕另外一项操作后返回继续执行当前操作流
<Params> 操作中来自于外部的参数
Name - 参数名称定义,注意:每个操作下的Param Name必须唯一
ValueType - 参数的类型定义
DefaultValue - 参数的默认值(如果在信息传输中没有设定该值的话,就自动采用默认值;如果默认值未设,则默认为Null)
ParamModifier - 参数的Modifier; 默认未设, 可以为 "out" "ref" 或空
<Result> 定义每个ManagerFlow的返回值;为设定则默认为 void
<EndResults> 用于设定整个操作所需要返回的结果,其内部的ReferenceName 即设定整个操作流中所应用和生成的数据中需要返回的变量;
代码中,ActionRunner.cs 将会以object[] 的形式返回所有需要返回的内容
ReturnTrueOrFalseOnly : 如果此属性为True, 则EndResults内所有子项均被忽略,ActionRunner.cs 的object[] 返回值仅包含一个True/False 结果,代表
此操作的最终结果(其中任何一操作流失败均为失败)
-->
<Actions>
<Action Name="CreateNewUser">
<Flows>
<ManagerFlow Name="InitCreateUser" ClassName="WebCider.PortalBuilder.Framework.Base.PortalUserManager"
AssemblyName="WebCider.PortalBuilder.Framework"
MethodName="CreateNewUser" >
<Params>
<Param Name="NewUserObject" ValueType="WebCider.PortalBuilder.Common.Base.PortalUser" DefaultValue="Null" ParamModifier="out" />
</Params>
<Result Name="CreateUserResult" ClassName="WebCider.PortalBuilder.Docs.DocCollection" AssemblyName="WebCider.PortalBuilder" />
</ManagerFlow>
<ActionFlow Name="SendEmail" AppKey="" />
</Flows>
<EndResults ReturnTrueOrFalseOnly="false">
<ReferenceName Name="NewUserObject" />
<ReferenceName Name="CreateUserResult" />
</EndResults>
</Action>
</Actions>
</ActionGroup>
</Application>
</PortalBuilderActions>
后台中调用和实现反射动态调用方法的代码:
public class ActionRunner
{
public static object[] Run(string codeIdentifier, object[] paramList, Guid applicationKey = default(Guid))
{
//获取Action
string actionXmlFilePath = System.AppDomain.CurrentDomain.BaseDirectory + "/" + Common.Global.GlobalConfig.ConfigurationFiles.PortalBuilderActionXML;
if (applicationKey != default(Guid))
actionXmlFilePath = AppManager.GetIntallationPath(applicationKey);
Common.Configurations.PBActions.Action runnerAction = ActionXMLParser.GetAction(codeIdentifier, actionXmlFilePath);
//创建Action所有参数值列表
Dictionary<string, object> fullParamList = new Dictionary<string, object>();
if (runnerAction != null && runnerAction.Flows != null && runnerAction.Flows.Count > 0)
{
foreach (Flow flow in runnerAction.Flows)
{
ActionFlow(paramList, fullParamList, flow);
}
if (runnerAction.ReturnTrueOrFalseOnly)
{
return new object[] { true };
}
else
{
if (runnerAction.EndResults != null && runnerAction.EndResults.Count > 0)
{
List<object> returningValues = new List<object>();
foreach (EndResult endResult in runnerAction.EndResults)
{
var objValue = (from item in fullParamList
where item.Key.ToLower() == endResult.Name.ToLower()
select item.Value).FirstOrDefault();
if (objValue != null)
{
endResult.Value = objValue;
returningValues.Add(objValue);
}
}
return returningValues.ToArray();
}
else return null;
}
}
else
{
if (runnerAction.ReturnTrueOrFalseOnly) return new object[] { false };
else return null;
};
}
private static void ActionFlow(object[] paramList, Dictionary<string, object> fullParamList, Flow flow)
{
if (flow is ManagerFlow)
{
ManagerFlow mFlow = (ManagerFlow)flow;
try
{
List<Type> paramTypes = new List<Type>();
if (mFlow.Params != null && mFlow.Params.Count > 0)
{
if (mFlow.Params.Count != paramList.Length) throw new WebCiderException("实际传入的参数数量与XML中定义的参数数量不符!");
foreach (Param param in mFlow.Params)
{
Type type;
if (!string.IsNullOrEmpty(param.ParamModifier))
{
type = Type.GetType(param.ValueType, true, true).MakeByRefType();
}
else
type = Type.GetType(param.ValueType, true, true);
paramTypes.Add(type);
fullParamList.Add(param.Name, paramList[paramTypes.IndexOf(type)]);
}
}
MethodInfo methodInfo = Type.GetType(mFlow.ClassName + "," + mFlow.AssemblyName, true, true).GetMethod(mFlow.MethodName, BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, paramTypes.ToArray(), null);
if (methodInfo == null)
throw new WebCiderException("获取XML定义类或类方法失败!");
object vResult = methodInfo.Invoke(null, BindingFlags.InvokeMethod, null, paramList, null);
if (vResult != null)
{
fullParamList.Add(mFlow.Result.Name, vResult);
}
}
catch (Exception ex)
{
WebCiderHelper.Logger.Error("严重系统错误:解析操作集XML时失败([" + mFlow.ClassName + "," + mFlow.AssemblyName + "->" + mFlow.MethodName + "):" + ex.Message, ex);
throw new WebCiderException("严重系统错误:解析操作集XML时失败([" + mFlow.ClassName + "," + mFlow.AssemblyName + "->" + mFlow.MethodName + "):" + ex.Message, ex);
}
}
else if (flow is ActionFlow)
{
ActionFlow aFlow = (ActionFlow)flow;
Common.Configurations.PBActions.Action flowAction = ActionXMLParser.GetAction(aFlow.Name, AppManager.GetIntallationPath(aFlow.ApplicationKey));
if (flowAction != null)
{
ActionFlow(paramList, fullParamList, aFlow);
}
else
{
WebCiderHelper.Logger.Error("严重系统错误:解析操作集XML时失败 - [" + aFlow.ApplicationKey + "] 的应用程序不存在或有错无法使用.");
throw new WebCiderException("严重系统错误:解析操作集XML时失败 - [" + aFlow.ApplicationKey + "] 的应用程序不存在或有错无法使用.");
}
}
}
}
以上代码引用了工作流引擎概念 仅供Portal Builder 开源门户系统开发者讨论研究 有看不懂的地方还请见谅,有问题可以到 http://bbs.oelite.com 进行进一步讨论