环境:Unity2017、.NET4.6
问题出现描述:自定义了JSON格式转换异常类,通过反射Invoke反射方法,抛出异常时,捕捉的异常是System.Reflection.TargetInvocationException而不是JSON格式转换异常。
源码简化如下:
/// <summary>
/// JSON格式转换类
/// </summary>
public static class JSonConvert
{
public static void Convert()
{
throw new JsonToClassEX("转换失败");
}
}
/// <summary>
/// JSON格式异常类
/// </summary>
public class JsonToClassEX : Exception
{
public JsonToClassEX(string message) : base(message)
{
}
}
反射方法捕捉异常
/// <summary>
/// 反射方法捕捉异常
/// </summary>
public class NewBehaviourScript : MonoBehaviour
{
void Start()
{
try
{
Type t = typeof(JSonConvert);
MethodInfo method = t.GetMethod("Convert");
method.Invoke(method.ReflectedType, null);
}
catch (JsonToClassEX e)
{
Debug.LogError("JsonToClassEX:" + e.Message);
}
catch (Exception e)
{
Debug.Log(e.GetType());
Debug.Log(e.InnerException.GetType());
Debug.LogError("Exception:" + e.Message);
}
}
}
输出结果:
可以看到catch (JsonToClassEX e)块并没有进入,而是通过catch (Exception e)块捕捉到。
此外捕捉的异常是:System.Reflection.TargetInvocationException,而我们自定义的异常类被封成了异常的的InnerException属性。
分析原因:
这是由于CLR在调用反射方法,改变了异常,重新抛出了异常,但保留了JSON格式异常的堆栈信息。这是由于.NET内部机制导致。
解决方法:
第一种:在catch (Exception e)或catch (TargetInvocationException e) 处理异常
既然被封成了内部异常,那么我直接可以通过InnerException属性判断类型进行处理。
catch (Exception e) when (e.InnerException.GetType() == typeof(JsonToClassEX))
{
//处理异常
}
第二种:我就是想捕捉到JSON格式异常,我不要通过InnerException属性(真是任性呢)
可以通过在反射方法内捕捉,修改JSonConvert类Convert方法如:
public static void Convert()
{
try
{
throw new JsonToClassEX("转换失败");
}
catch (Exception e)
{
Debug.LogWarning(e);
//throw;如果想同时捕捉到argetInvocationException异常,请取消注释
}
}
这样捕捉到JsonToClassEX异常就不会抛出,若想继续捕捉到TargetInvocationException 异常就取消throw的注释。