如何追中异常,减少debug时间

今天在debug的时候,又出现了空指针,我这次真的火了!每次遇到空指针,.net给出的信息总是非常的少,我根本不知道是哪里Throw出来的,只能反复检查代码。
思路大概是:

  1. 获取exception的调用堆栈。

  2. 获取exception相关的这个方法的方法的IL代码

  3. 结合excpetion的IL偏移量和方法的IL,把调用源找出来。

代码

   class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string hello3 = null;

                hello3 = hello3.ToUpper();
            }
            catch (Exception ex)
            {
                //获取调用堆栈

                StackTrace trace = new StackTrace(ex, true);

                StackFrame frame = trace.GetFrame(0);

                int offset = frame.GetILOffset();

                byte[] il = frame.GetMethod().GetMethodBody().GetILAsByteArray();


                //获取调用指令

                offset++;

                ushort instruction = il[offset++];


                //打开潘多拉魔盒

                ILGlobals global = new ILGlobals();

                global.LoadOpCodes();


                //翻译

                OpCode code = OpCodes.Nop;

                if (instruction != 0xfe)
                {
                    code = global.SingleByteOpCodes[(int)instruction];
                }
                else
                {
                    instruction = il[offset++];
                    code = global.MultiByteOpCodes[(int)instruction];
                    instruction = (ushort)(instruction | 0xfe00);
                }


                //获取方法信息

                int metadataToken = ReadInt32(il, ref offset);

                MethodBase callmethod = frame.GetMethod().Module.ResolveMethod(metadataToken,
                     frame.GetMethod().DeclaringType.GetGenericArguments(),
                     frame.GetMethod().GetGenericArguments());

                //完成

                Console.WriteLine(callmethod.DeclaringType + "." + callmethod.Name);

                Console.Read();
            }

        }

        private static int ReadInt32(byte[] il, ref int position)
        {
            return (((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18));
        }

    }

    public class ILGlobals
    {
        private OpCode[] multiByteOpCodes;

        private OpCode[] singleByteOpCodes;

        /// <summary>
        /// Loads the OpCodes for later use.
        /// </summary>
        public void LoadOpCodes()
        {
            singleByteOpCodes = new OpCode[0x100];
            multiByteOpCodes = new OpCode[0x100];
            FieldInfo[] infoArray1 = typeof(OpCodes).GetFields();
            for (int num1 = 0; num1 < infoArray1.Length; num1++)
            {
                FieldInfo info1 = infoArray1[num1];
                if (info1.FieldType == typeof(OpCode))
                {
                    OpCode code1 = (OpCode)info1.GetValue(null);
                    ushort num2 = (ushort)code1.Value;
                    if (num2 < 0x100)
                    {
                        singleByteOpCodes[(int)num2] = code1;
                    }
                    else
                    {
                        if ((num2 & 0xff00) != 0xfe00)
                        {
                            throw new Exception("Invalid OpCode.");
                        }
                        multiByteOpCodes[num2 & 0xff] = code1;
                    }
                }
            }
        }

        /// <summary>
        /// Retrieve the friendly name of a type
        /// </summary>
        /// <param name="typeName">
        /// The complete name to the type
        /// </param>
        /// <returns>
        /// The simplified name of the type (i.e. "int" instead f System.Int32)
        /// </returns>
        public static string ProcessSpecialTypes(string typeName)
        {
            string result = typeName;
            switch (typeName)
            {
                case "System.string":
                case "System.String":
                case "String":
                    result = "string"; break;
                case "System.Int32":
                case "Int":
                case "Int32":
                    result = "int"; break;
            }
            return result;
        }


        public OpCode[] MultiByteOpCodes
        {
            get { return multiByteOpCodes; }
        }

        public OpCode[] SingleByteOpCodes
        {
            get { return singleByteOpCodes; }
        }
    }

该文的应用场景估计是:(1)程序在一台机器上已经开发调试OK了;(2)Release编译并部署到另一台机器。在这里出现了NRE的话,.NET FW是不能给你这么多的信息的,只能重新到开发机器进行调试。所以,LZ这种方法还是不错的。

但是,更明智的方法是进行精密的异常管理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值