问题说明
我们单位开发的程序,除了在我们本单位(单位A)使用之外,还在其它单位(单位B)使用,区别就是我们单位一直在更新服务端的接口,但是B单位是很久才更新一次。因此在我们单位和单位B中服务的接口不一样。最近碰到一个问题,有个函数,假设名称为FuncCalcu,在我们单位的服务中有该函数,在单位B中没有这个函数。在客户端使用时,使用全局类中的变量IsExistedFuncCalcu来判断是否要调用FuncCalcu,调用代码类似于下面:
if(IsExistedFuncCalcu)
{
FunCalcu();
}
但是实际代码在B单位运行时,会报在服务端引用程序集中无法找到函数FunCalcu,即使在代码运行过程中没有调到FuncCalcu函数,也会报这个错。错误还原的示例程序在https://github.com/guochao2299/DelegateInvokeTest/tree/master/DelegateInvokeTest/%E9%97%AE%E9%A2%98%E8%BF%98%E5%8E%9F%E4%BB%A3%E7%A0%81中可以找到。即便不会调用该函数,运行程序时依然会报错:
原因分析
通过对代码进行调试分析,发现即便没有直接调用函数FunCalcu,如下面代码所示,在调用DoTheOperation时,即便时没有使用MathLib.Sub函数,程序也会检查引用的程序集中是否包含MathLib.Sub函数,如果不包含,就会报错。
private float DoTheOperation(int a,int b,int optType)
{
switch(optType)
{
case 0:
return MathCalcLib.MathLib.Add(a , b);
case 1:
if (MathCalcLib.MathLib.IsSupportSubOpt)
{
return MathCalcLib.MathLib.Sub(a, b);
}
break;
case 2:
return MathCalcLib.MathLib.Multy(a, b);
case 3:
return MathCalcLib.MathLib.Div(a, b);
}
throw new Exception("未识别的操作符");
}
解决方案
为了防止应用系统报错,可以采用反射的方式调用Sub函数,这样即便程序集中不包含Sub函数,程序在运行过程中也不会报错,示例代码如下所示:
if (MathCalcLib.MathLib.IsSupportSubOpt)
{
System.Reflection.MethodInfo mInfo = typeof(MathCalcLib.MathLib).GetMethod("Sub", System.Reflection.BindingFlags.Static);
if(mInfo==null)
{
MessageBox.Show("MathCalcLib.MathLib类中不包含静态函数Sub");
return;
}
return (float)mInfo.Invoke(null, new object[] { a, b });
}
反射的方式可以避免因为某个函数不存在导致程序出现异常,但是还有其它方式可以避免出错,例如使用代理方式,也即采用反射方式给代理赋值,如果存在函数Sub,则将Sub函数赋值给代理,如果不存在,则给代理赋默认值,代码如下所示,至此问题解决:
if (MathCalcLib.MathLib.IsSupportSubOpt)
{
System.Reflection.MethodInfo mInfo = typeof(MathCalcLib.MathLib).GetMethod("Sub", System.Reflection.BindingFlags.Public| System.Reflection.BindingFlags.Static);
if (mInfo == null)
{
MessageBox.Show("MathCalcLib.MathLib类中不包含静态函数Sub");
}
Delegate d= Delegate.CreateDelegate(typeof(Func<int, int, float>), mInfo);
result = d as Func<int, int, float>;
break;
}
else
{
result = delegate (int a, int b)
{
return 0;
};
}
完整的测试代码放在了如下网址中:
https://github.com/guochao2299/DelegateInvokeTest/upload/DelegateVersion
参考文献:
[1]https://blog.csdn.net/soapcoder92/article/details/51027547
[2]https://blog.csdn.net/lxrj2008/article/details/61255224