C#有趣的VS扩展DebuggerVisualizer

来源:互联网 发布:c语言混淆工具 编辑:程序博客网 时间:2024/06/01 20:27

转载自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD5/20150925/9803.html


公司的研发平台底层封装了一种类似于DataTable的数据结构,具有行列特性但是直接基于键值对,每次调试时想要查看其中的内容都非常困难。不由得想起第一次使用VS调试Dataset时候弹出的哪个框,鉴于此,搜索了大量资料,在走过一些弯路后终于尝试成功,特记录于此,以备后效。

1.几个主要的概念

  1.DebuggerVisualizer:MSDN的说明中描述了一些基础的步骤,这个类位于System.Diagnostics命名空间下,用来制定类型的可视化工具属性。另外,在Microsoft.VisualStudio.DebuggerVisualizer.dll程序集中,封装了诸如调试时弹出窗口的一些接口和默认实现。

     2.DialogDebuggerVisualizer,Microsoft.VisualStudio.DebuggerVisualizer.dll程序集中用来弹出调试时窗口的基类。

   3.VisualizerObjectSource,负责将当前要可视化的对象序列化或者反序列化,以便在组件间进行传输。这里的序列化说明后续的对象最好事先了ISerializable接口或者标记为Serializable。如果不是,默认的对象是报无法序列化错误,后面我们介绍如何处理。

    4.VisualizerDevelopmentHost,可视化工具开发宿主,并调用宿主以显示可视化工具。后续会用来测试。

   5.微软提供了官方的DebuggerVisualizer模板类,可以下载,不过目前我还没找到。

    DebuggerVisualizer对于开发人员具有比较重要的意义,能够将一些不便于调试、查看和编辑的对象可视化,方便查看和编辑数据。

2.主要实现

   相关的代码非常简单,CodeProject上有人用10行代码实现了一个图片调试工具,我们就以这个代码举例。

[assembly: System.Diagnostics.DebuggerVisualizer(typeof(ImageVisualizer.DebuggerSide),typeof(VisualizerObjectSource),    Target = typeof(System.Drawing.Image),Description = "Image Visualizer")]namespace ImageVisualizer{    public class DebuggerSide : DialogDebuggerVisualizer    {        override protected void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)        {            Image image = (Image)objectProvider.GetObject();                        Form form = new Form();            form.Text = string.Format("Width: {0}, Height: {1}", image.Width, image.Height);            form.ClientSize = new Size(image.Width, image.Height);            form.FormBorderStyle = FormBorderStyle.FixedToolWindow;                        PictureBox pictureBox = new PictureBox();            pictureBox.Image = image;            pictureBox.Parent = form;            pictureBox.Dock = DockStyle.Fill;            windowService.ShowDialog(form);            // 如果在弹出窗口修改对象的数据,可以将objectProvider对象传给Form            // 然后将修改后的数据传输回去            // 需要注意,必须判断当前调试状态是否允许替换原本的调试初始值            //TextBox text = win.FindName("txtValue") as TextBox;            //Int32 newValue = Convert.ToInt32(text.Text);            //if (objProvider.IsObjectReplaceable)            //{            //    objProvider.ReplaceObject(newValue);            //}        }    }

  命名空间上的声明可以让VS识别该程序集,后续DebuggerSide 类重写了Show方法,通过IDialogVisualizerService的实例创建一个弹出窗口,objectProvider则将对象从编

此文来自: 马开东博客 转载请注明出处 网址: http://www.makaidong.com

辑器中传输到处理函数以便进行后续处理。上文处理的对象是Image,如果该对象是不可序列化的对象,那么我们需要利用System.Diagnostics.DebuggerVisualizer的第二个参数。

  调试器端和调试对象端使用 VisualizerObjectSource 和 IVisualizerObjectProvider 相互通信。所以,对于未标记为序列化的对象,我们需要重写该类的部分方法,将对象以可序列化的方式进行传输。简而言之,对对象进行封装处理。

    public class ImageSource : VisualizerObjectSource    {        /// <summary>        /// 用来将输入的数据进行处理和封装,转换为流以便在组件间通讯        /// </summary>        /// <param name="target">当前查看的对象</param>        /// <param name="outgoingData">输出流</param>        public override void GetData(object target, System.IO.Stream outgoingData)        {            // 获取调试对象            Image image = target as Image;            // 将不可序列化的对象转换为可序列化对象            // Image本身是可序列化的,此处举例说明            SerializableImage newImage = image as SerializableImage;            //  传输对象            base.GetData(newImage, outgoingData);        }    }    public class SerializableImage : Image, ISerializable    {        // TODO: 序列化对象    }

   这个WPF的教程更加仔细的介绍了一些步骤,包括如果更改调试变量的数据等。

  测试代码如下,任意创建控制台或者Winform等程序,启动即可调试:

        public static void TestVisualizer(object source)        {            // 直接使用当前自定义的调试器和数据处理对象类型,即可初始化进行测试            VisualizerDevelopmentHost visualizeHost = new VisualizerDevelopmentHost(source,                 typeof(DebuggerSide), typeof(ImageSource));            visualizeHost.ShowVisualizer();        }

    3.部署

  部署时也比较简单,直接将Dll复制到对应VS的安装目录下的\Common7\Packages\Debugger\Visualizers目录即可。你可以将下述命令修改保存为批处理,在程序集目录执行即可。

copy DictionaryVisualizer2010.dll "C:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers" /ycopy ListVisualizer2010.dll "C:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers" /ycopy VisualizerLib.dll "C:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers" /y

    4.说明

  作为一种比较重型的扩展,有些情况我们可能需要对一些List或者自定义对象,在调试时无需弹出窗口,而希望直接鼠标置于其上时显示如数量或者关键字等信息,那么可以直接使用DebuggerDisplay和DebuggerTypeProxy 进行处理。CodeProject也有文章介绍了这方面的东西。下面是一些复制来的代码:  

    using System;    using System.Collections;    using System.Data;    using System.Diagnostics;    using System.Reflection;    class DebugViewTest    {        // The following constant will appear in the debug window for DebugViewTest.         const string TabString = "    ";        // The following DebuggerBrowsableAttribute prevents the property following it         // from appearing in the debug window for the class.        [DebuggerBrowsable(DebuggerBrowsableState.Never)]        public static string y = "Test String";        static void Main()        {            Hashtable hash = new Hashtable();            MyHashtable myHashTable = new MyHashtable();            DataSet ds = new DataSet();            DataTable dt = new DataTable();            ds.Tables.Add(dt);            myHashTable.Add("one", 1);            myHashTable.Add("two", 2);            DBTable table = new DBTable();            //table.Columns.Add("TEST1");            //table.Columns.Add("TEST2");            //table.Columns.Add("TEST3");            //table.Rows.Add("1", "2", "3");            //table.Rows.Add("1", "2", "3");            //table.AcceptChanges();            Console.WriteLine(myHashTable.ToString());            Console.WriteLine("In Main.");        }    }    [DebuggerDisplay("{value}", Name = "{key}")]    internal class KeyValuePairs    {        private IDictionary dictionary;        private object key;        private object value;        public KeyValuePairs(IDictionary dictionary, object key, object value)        {            this.value = value;            this.key = key;            this.dictionary = dictionary;        }    }    [DebuggerDisplay("Count = {Count}")]    [DebuggerTypeProxy(typeof(HashtableDebugView))]    class MyHashtable : Hashtable    {        private const string TestString = "This should not appear in the debug window.";        internal class HashtableDebugView        {            private Hashtable hashtable;            public const string TestString = "This should appear in the debug window.";            public HashtableDebugView(Hashtable hashtable)            {                this.hashtable = hashtable;            }            [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]            public KeyValuePairs[] Keys            {                get                {                    KeyValuePairs[] keys = new KeyValuePairs[hashtable.Count];                    int i = 0;                    foreach (object key in hashtable.Keys)                    {                        keys[i] = new KeyValuePairs(hashtable, key, hashtable[key]);                        i++;                    }                    return keys;                }            }        }    }

原创粉丝点击