zoukankan      html  css  js  c++  java
  • .NET获取枚举DescriptionAttribute描述信息性能改进的多种方法

    一. DescriptionAttribute的普通使用方式

    1.1 使用示例

      DescriptionAttribute特性可以用到很多地方,比较常见的就是枚举,通过获取枚举上定义的描述信息在UI上显示,一个简单的枚举定义:

    public enum EnumGender
            {
                None,
                [System.ComponentModel.Description("")]
                Male,
                [System.ComponentModel.Description("")]
                Female,
                Other,
            }

      本文不讨论DescriptionAttribute的其他应用场景,也不关注多语言的实现,只单纯的研究下获取枚举描述信息的方法。

      一般比较常见的获取枚举描述信息的方法如下,可以在园子里搜索类似的代码非常多。

    public static string GetDescriptionOriginal(this Enum @this)
            {
                var name = @this.ToString();
                var field = @this.GetType().GetField(name);
                if (field == null) return name;
                var att = System.Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute), false);
                return att == null ? field.Name : ((DescriptionAttribute)att).Description;
            }

      简单测试下:

    Console.WriteLine(EnumGender.Female.GetDescriptionOriginal());
    Console.WriteLine(EnumGender.Male.GetDescriptionOriginal());
    Console.WriteLine(EnumGender.Other.GetDescriptionOriginal());
    //输出结果:



    Other

    1.2 上面的实现代码的问题

      首先要理解特性是什么?

    特性

        Attribute特性就是关联了一个目标对象的一段配置信息,存储在dll内的元数据。它本身没什么意义,可以通过反射来获取配置的特性信息。

      因此主要问题其实就是反射造成的严重性能问题:

    • 1.每次调用都会使用反射,效率慢!
    • 2.每次调用反射都会生成新的DescriptionAttribute对象,哪怕是同一个枚举值。造成内存、GC的极大浪费!
    • 3.好像不支持位域组合对象!
    • 4.这个地方的方法参数是Enum,Enum是枚举的基类,他是一个引用类型,而枚举是值类型,该方法会造成装箱,不过这个问题好像是不可避免的。

      性能到底有多差呢?代码来实测一下:

            [Test]
            public void GetDescriptionOriginal_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionOriginal();
                        }
                    });
                });
            }
    
    //输出结果:
    80
    TimeSpan:79,881.0000ms //共消耗了将近80秒
    MemoryUsed:-1,652.7970KB
    CollectionCount(0):7,990.00  //0代GC回收了7千多次,因为创建了大量的DescriptionAttribute对象

      其中this.GetTestEnums();方法使用获取一个枚举值集合,用于测试的,集合大小80,执行100w次,相当于执行了8000w次GetDescriptionOriginal方法。

      TestHelper.InvokeAndWriteAll方法是用来计算执行前后的时间、内存消耗、0代GC回收次数的,文末附录中给出了代码,由于内存回收的原因,内存消耗计算其实不准确的,不过可以参考第三个指标0代GC回收次数。

    二. 改进的DescriptionAttribute方法

      知道了问题原因,解决就好办了,基本思路就是把获取到的文本值缓存起来,一个枚举值只反射一次,这样性能问题就解决了。

    2.1 使用字典缓存+锁

      因为使用静态变量字典来缓存值,就涉及到线程安全,需要使用锁(做了双重检测),具体方法:

    private static Dictionary<Enum, string> _LockDictionary = new Dictionary<Enum, string>();
            public static string GetDescriptionByDictionaryWithLocak(this Enum @this)
            {
                if (_LockDictionary.ContainsKey(@this)) return _LockDictionary[@this];
                Monitor.Enter(_obj);
                if (!_LockDictionary.ContainsKey(@this))
                {
                    var value = @this.GetDescriptionOriginal();
                    _LockDictionary.Add(@this, value);
                }
                Monitor.Exit(_obj);
                return _LockDictionary[@this];
            }

      来测试一下,测试数据、次数和1.2的GetDescriptionOriginal_Test相同,效率有很大的提升,只有一次内存回收。

    [Test]
            public void GetDescriptionByDictionaryWithLocak_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByDictionaryWithLocak();
                        }
                    });
                });
            }
    
    //测试结果:
    80
    TimeSpan:1,860.0000ms
    MemoryUsed:159.2422KB
    CollectionCount(0):1.00

    2.2 使用字典缓存+异常(不走寻常路的方式)

      还是先看看实现方法吧!

    private static Dictionary<Enum, string> _ExceptionDictionary = new Dictionary<Enum, string>();
            public static string GetDescriptionByDictionaryWithException(this Enum @this)
            {
                try
                {
                    return _ExceptionDictionary[@this];
                }
                catch (KeyNotFoundException)
                {
                    Monitor.Enter(_obj);
                    if (!_ExceptionDictionary.ContainsKey(@this))
                    {
                        var value = @this.GetDescriptionOriginal();
                        _ExceptionDictionary.Add(@this, value);
                    }
                    Monitor.Exit(_obj);
                    return _ExceptionDictionary[@this];
                }
            }

      假设我们的使用场景是这样的:项目定义的枚举并不多,但是用其描述值很频繁,比如定义了一个用户性别枚举,用的地方很多,使用频率很高。

      上面GetDescriptionByDictionaryWithLocak的方法中,第一句代码“if (_LockDictionary.ContainsKey(@this)) ”就是验证是否包含枚举值。在2.1的测试中执行了8000w次,其中只有80次(总共只有80个枚举值用于测试)需要这句代码“if (_LockDictionary.ContainsKey(@this)) ”,其余的直接取值就可了。基于这样的考虑,就有了上面的方法GetDescriptionByDictionaryWithException。

      来测试一下,看看效果吧!

    [Test]
            public void GetDescriptionByDictionaryWithException_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByDictionaryWithException();
                        }
                    });
                });
            }
    
    //测试结果:
    80
    TimeSpan:1,208.0000ms
    MemoryUsed:230.9453KB
    CollectionCount(0):1.00

      测试结果来看,基本上差不多,在时间上略微快乐一点点,1,208.0000ms:1,860.0000ms,执行8000w次快600毫秒,好像差别也不大啊,这是为什么呢?

      这个其实就是Dictionary的问题了,Dictionary内部使用散列算法计算存储地址,其查找的时间复杂度为o(1),他的查找效果是非常快的,而本方法中利用了异常处理,异常捕获本身是有一定性能影响的。

    2.3 推荐简单方案:ConcurrentDictionary

      ConcurrentDictionary是一个线程安全的字典类,代码:

    private static ConcurrentDictionary<Enum, string> _ConcurrentDictionary = new ConcurrentDictionary<Enum, string>();
            public static string GetDescriptionByConcurrentDictionary(this Enum @this)
            {
                return _ConcurrentDictionary.GetOrAdd(@this, (key) =>
                {
                    var type = key.GetType();
                    var field = type.GetField(key.ToString());
                    return field == null ? key.ToString() : GetDescription(field);
                });
            }

      测试代码及测试结果:

    [Test]
            public void GetDescriptionByConcurrentDictionary_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByConcurrentDictionary();
                        }
                    });
                });
            }
    
    //测试结果:
    80
    TimeSpan:1,303.0000ms
    MemoryUsed:198.0859KB
    CollectionCount(0):1.00

    2.4 正式的代码

      综上所述,解决了性能问题、位域枚举问题的正式的代码:

    /// <summary>
            /// 获取枚举的描述信息(Descripion)。
            /// 支持位域,如果是位域组合值,多个按分隔符组合。
            /// </summary>
            public static string GetDescription(this Enum @this)
            {
                return _ConcurrentDictionary.GetOrAdd(@this, (key) =>
                {
                    var type = key.GetType();
                    var field = type.GetField(key.ToString());
                    //如果field为null则应该是组合位域值,
                    return field == null ? key.GetDescriptions() : GetDescription(field);
                });
            }
    
            /// <summary>
            /// 获取位域枚举的描述,多个按分隔符组合
            /// </summary>
            public static string GetDescriptions(this Enum @this, string separator = ",")
            {
                var names = @this.ToString().Split(',');
                string[] res = new string[names.Length];
                var type = @this.GetType();
                for (int i = 0; i < names.Length; i++)
                {
                    var field = type.GetField(names[i].Trim());
                    if (field == null) continue;
                    res[i] = GetDescription(field);
                }
                return string.Join(separator, res);
            }
    
            private static string GetDescription(FieldInfo field)
            {
                var att = System.Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute), false);
                return att == null ? field.Name : ((DescriptionAttribute)att).Description;
            }

     版权所有,文章来源:http://www.cnblogs.com/anding

    个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

    附录:

    1.EnumExtension.cs代码: 

       public static class EnumExtension
        {
            /// <summary>
            /// 获取枚举的描述信息(Descripion)。
            /// 支持位域,如果是位域组合值,多个按分隔符组合。
            /// </summary>
            public static string GetDescription(this Enum @this)
            {
                return _ConcurrentDictionary.GetOrAdd(@this, (key) =>
                {
                    var type = key.GetType();
                    var field = type.GetField(key.ToString());
                    //如果field为null则应该是组合位域值,
                    return field == null ? key.GetDescriptions() : GetDescription(field);
                });
            }
    
            /// <summary>
            /// 获取位域枚举的描述,多个按分隔符组合
            /// </summary>
            public static string GetDescriptions(this Enum @this, string separator = ",")
            {
                var names = @this.ToString().Split(',');
                string[] res = new string[names.Length];
                var type = @this.GetType();
                for (int i = 0; i < names.Length; i++)
                {
                    var field = type.GetField(names[i].Trim());
                    if (field == null) continue;
                    res[i] = GetDescription(field);
                }
                return string.Join(separator, res);
            }
    
            private static string GetDescription(FieldInfo field)
            {
                var att = System.Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute), false);
                return att == null ? field.Name : ((DescriptionAttribute)att).Description;
            }
    
            /****************** test methods ******************/
    
            public static string GetDescriptionOriginal(this Enum @this)
            {
                var name = @this.ToString();
                var field = @this.GetType().GetField(name);
                if (field == null) return name;
                var att = System.Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute), false);
                return att == null ? field.Name : ((DescriptionAttribute)att).Description;
            }
    
            private static Dictionary<Enum, string> _LockDictionary = new Dictionary<Enum, string>();
            public static string GetDescriptionByDictionaryWithLocak(this Enum @this)
            {
                if (_LockDictionary.ContainsKey(@this)) return _LockDictionary[@this];
                Monitor.Enter(_obj);
                if (!_LockDictionary.ContainsKey(@this))
                {
                    var value = @this.GetDescriptionOriginal();
                    _LockDictionary.Add(@this, value);
                }
                Monitor.Exit(_obj);
                return _LockDictionary[@this];
            }
    
            private static Dictionary<Enum, string> _ExceptionDictionary = new Dictionary<Enum, string>();
            public static string GetDescriptionByDictionaryWithException(this Enum @this)
            {
                try
                {
                    return _ExceptionDictionary[@this];
                }
                catch (KeyNotFoundException)
                {
                    Monitor.Enter(_obj);
                    if (!_ExceptionDictionary.ContainsKey(@this))
                    {
                        var value = @this.GetDescriptionOriginal();
                        _ExceptionDictionary.Add(@this, value);
                    }
                    Monitor.Exit(_obj);
                    return _ExceptionDictionary[@this];
                }
            }
    
            public static object _obj = new object();
            private static ConcurrentDictionary<Enum, string> _ConcurrentDictionary = new ConcurrentDictionary<Enum, string>();
            public static string GetDescriptionByConcurrentDictionary(this Enum @this)
            {
                return _ConcurrentDictionary.GetOrAdd(@this, (key) =>
                {
                    var type = key.GetType();
                    var field = type.GetField(key.ToString());
                    return field == null ? key.ToString() : GetDescription(field);
                });
            }
        }
    View Code

    2.测试类EnumTest.cs代码: 

        [TestFixture]
        public class EnumTest
        {
            [Test]
            public void SimpleTest()
            {
                Console.WriteLine(EnumGender.Female.GetDescriptionOriginal());
                Console.WriteLine(EnumGender.Male.GetDescriptionOriginal());
                Console.WriteLine(EnumGender.Other.GetDescriptionOriginal());
    
                var t1 = EnumGender.Male | EnumGender.Female;
                Console.WriteLine((t1 & EnumGender.Male) == EnumGender.Male);
                Console.WriteLine(t1 & ~EnumGender.Male);
                Console.WriteLine(Enum.IsDefined(typeof(EnumGender), 0));
            }
    
            [Test]
            public void GetDescriptionOriginal_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionOriginal();
                        }
                    });
                });
            }
    
            [Test]
            public void GetDescriptionByDictionaryWithLocak_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByDictionaryWithLocak();
                        }
                    });
                });
            }
    
            [Test]
            public void GetDescriptionByDictionaryWithException_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByDictionaryWithException();
                        }
                    });
                });
            }
    
            [Test]
            public void GetDescriptionByConcurrentDictionary_Test()
            {
                var enums = this.GetTestEnums();
                Console.WriteLine(enums.Count);
                TestHelper.InvokeAndWriteAll(() =>
                {
                    System.Threading.Tasks.Parallel.For(0, 1000000, (i, obj) =>
                    {
                        foreach (var item in enums)
                        {
                            var a = item.GetDescriptionByConcurrentDictionary();
                        }
                    });
                });
            }
    
            private List<Enum> GetTestEnums()
            {
                List<Enum> res = new List<Enum>();
                res.Add(EnumMutliFTest.T1);
                res.Add(EnumMutliFTest.T2);
                res.Add(EnumMutliFTest.T3);
                res.Add(EnumMutliFTest.T4);
                res.Add(EnumMutliFTest.T5);
                res.Add(EnumMutliFTest.T6);
                res.Add(EnumMutliFTest.T7);
                res.Add(EnumMutliFTest.T8);
                res.Add(EnumMutliFTest.T9);
                res.Add(EnumMutliFTest.T10);
                res.Add(EnumMutliFTest.T11);
                res.Add(EnumMutliFTest.T12);
                res.Add(EnumMutliFTest.T13);
                res.Add(EnumMutliFTest.T14);
                res.Add(EnumMutliFTest.T15);
                res.Add(EnumMutliFTest.T16);
                res.Add(EnumMutliFTest.T17);
                res.Add(EnumMutliFTest.T18);
                res.Add(EnumMutliFTest.T19);
                res.Add(EnumMutliFTest.T20);
                res.Add(EnumMutliFTest.T21);
                res.Add(EnumMutliFTest.T22);
                res.Add(EnumMutliFTest.T23);
                res.Add(EnumMutliFTest.T24);
                res.Add(EnumMutliFTest.T25);
                res.Add(EnumMutliFTest.T26);
                res.Add(EnumMutliFTest.T27);
                res.Add(EnumMutliFTest.T28);
                res.Add(EnumMutliFTest.T29);
                res.Add(EnumMutliFTest.T30);
                res.Add(EnumMutliFTest.T31);
                res.Add(EnumMutliFTest.T32);
                res.Add(EnumMutliFTest.T33);
                res.Add(EnumMutliFTest.T34);
                res.Add(EnumMutliFTest.T35);
                res.Add(EnumMutliFTest.T36);
                res.Add(EnumMutliFTest.T37);
                res.Add(EnumMutliFTest.T38);
                res.Add(EnumMutliFTest.T3);
                res.Add(EnumMutliFTest.T18);
    
                res.Add(EnumMutliFTest2.T21);
                res.Add(EnumMutliFTest2.T22);
                res.Add(EnumMutliFTest2.T23);
                res.Add(EnumMutliFTest2.T24);
                res.Add(EnumMutliFTest2.T25);
                res.Add(EnumMutliFTest2.T26);
                res.Add(EnumMutliFTest2.T27);
                res.Add(EnumMutliFTest2.T28);
                res.Add(EnumMutliFTest2.T29);
                res.Add(EnumMutliFTest2.T210);
                res.Add(EnumMutliFTest2.T211);
                res.Add(EnumMutliFTest2.T212);
                res.Add(EnumMutliFTest2.T213);
                res.Add(EnumMutliFTest2.T214);
                res.Add(EnumMutliFTest2.T215);
                res.Add(EnumMutliFTest2.T216);
                res.Add(EnumMutliFTest2.T217);
                res.Add(EnumMutliFTest2.T218);
                res.Add(EnumMutliFTest2.T219);
                res.Add(EnumMutliFTest2.T220);
                res.Add(EnumMutliFTest2.T221);
                res.Add(EnumMutliFTest2.T222);
                res.Add(EnumMutliFTest2.T223);
                res.Add(EnumMutliFTest2.T224);
                res.Add(EnumMutliFTest2.T225);
                res.Add(EnumMutliFTest2.T226);
                res.Add(EnumMutliFTest2.T227);
                res.Add(EnumMutliFTest2.T228);
                res.Add(EnumMutliFTest2.T229);
                res.Add(EnumMutliFTest2.T230);
                res.Add(EnumMutliFTest2.T231);
                res.Add(EnumMutliFTest2.T232);
                res.Add(EnumMutliFTest2.T233);
                res.Add(EnumMutliFTest2.T234);
                res.Add(EnumMutliFTest2.T235);
                res.Add(EnumMutliFTest2.T236);
                res.Add(EnumMutliFTest2.T237);
                res.Add(EnumMutliFTest2.T238);
                res.Add(EnumMutliFTest2.T23);
                res.Add(EnumMutliFTest2.T218);
    
                return res;
            }
    
            public enum EnumMutliFTest
            {
                [System.ComponentModel.Description("DT1")]
                T1,
                [System.ComponentModel.Description("DT2")]
                T2,
                [System.ComponentModel.Description("DT3")]
                T3,
                [System.ComponentModel.Description("DT4")]
                T4,
                [System.ComponentModel.Description("DT5")]
                T5,
                [System.ComponentModel.Description("DT6")]
                T6,
                [System.ComponentModel.Description("DT7")]
                T7,
                [System.ComponentModel.Description("DT8")]
                T8,
                [System.ComponentModel.Description("DT9")]
                T9,
                [System.ComponentModel.Description("DT10")]
                T10,
                [System.ComponentModel.Description("DT11")]
                T11,
                [System.ComponentModel.Description("DT12")]
                T12,
                [System.ComponentModel.Description("DT13")]
                T13,
                [System.ComponentModel.Description("DT14")]
                T14,
                [System.ComponentModel.Description("DT15")]
                T15,
                [System.ComponentModel.Description("DT16")]
                T16,
                [System.ComponentModel.Description("DT17")]
                T17,
                [System.ComponentModel.Description("DT18")]
                T18,
                [System.ComponentModel.Description("DT19")]
                T19,
                [System.ComponentModel.Description("DT20")]
                T20,
                [System.ComponentModel.Description("DT21")]
                T21,
                [System.ComponentModel.Description("DT22")]
                T22,
                [System.ComponentModel.Description("DT23")]
                T23,
                [System.ComponentModel.Description("DT24")]
                T24,
                [System.ComponentModel.Description("DT25")]
                T25,
                [System.ComponentModel.Description("DT26")]
                T26,
                [System.ComponentModel.Description("DT27")]
                T27,
                [System.ComponentModel.Description("DT28")]
                T28,
                [System.ComponentModel.Description("DT29")]
                T29,
                [System.ComponentModel.Description("DT30")]
                T30,
                [System.ComponentModel.Description("DT31")]
                T31,
                [System.ComponentModel.Description("DT32")]
                T32,
                [System.ComponentModel.Description("DT33")]
                T33,
                [System.ComponentModel.Description("DT34")]
                T34,
                [System.ComponentModel.Description("DT35")]
                T35,
                [System.ComponentModel.Description("DT36")]
                T36,
                [System.ComponentModel.Description("DT37")]
                T37,
                [System.ComponentModel.Description("DT38")]
                T38,
            }
    
            public enum EnumMutliFTest2
            {
                [System.ComponentModel.Description("DT21")]
                T21,
                [System.ComponentModel.Description("DT22")]
                T22,
                [System.ComponentModel.Description("DT23")]
                T23,
                [System.ComponentModel.Description("DT24")]
                T24,
                [System.ComponentModel.Description("DT25")]
                T25,
                [System.ComponentModel.Description("DT26")]
                T26,
                [System.ComponentModel.Description("DT27")]
                T27,
                [System.ComponentModel.Description("DT28")]
                T28,
                [System.ComponentModel.Description("DT29")]
                T29,
                [System.ComponentModel.Description("DT210")]
                T210,
                [System.ComponentModel.Description("DT211")]
                T211,
                [System.ComponentModel.Description("DT212")]
                T212,
                [System.ComponentModel.Description("DT213")]
                T213,
                [System.ComponentModel.Description("DT214")]
                T214,
                [System.ComponentModel.Description("DT215")]
                T215,
                [System.ComponentModel.Description("DT216")]
                T216,
                [System.ComponentModel.Description("DT217")]
                T217,
                [System.ComponentModel.Description("DT218")]
                T218,
                [System.ComponentModel.Description("DT219")]
                T219,
                [System.ComponentModel.Description("DT220")]
                T220,
                [System.ComponentModel.Description("DT221")]
                T221,
                [System.ComponentModel.Description("DT222")]
                T222,
                [System.ComponentModel.Description("DT223")]
                T223,
                [System.ComponentModel.Description("DT224")]
                T224,
                [System.ComponentModel.Description("DT225")]
                T225,
                [System.ComponentModel.Description("DT226")]
                T226,
                [System.ComponentModel.Description("DT227")]
                T227,
                [System.ComponentModel.Description("DT228")]
                T228,
                [System.ComponentModel.Description("DT229")]
                T229,
                [System.ComponentModel.Description("DT230")]
                T230,
                [System.ComponentModel.Description("DT231")]
                T231,
                [System.ComponentModel.Description("DT232")]
                T232,
                [System.ComponentModel.Description("DT233")]
                T233,
                [System.ComponentModel.Description("DT234")]
                T234,
                [System.ComponentModel.Description("DT235")]
                T235,
                [System.ComponentModel.Description("DT236")]
                T236,
                [System.ComponentModel.Description("DT237")]
                T237,
                [System.ComponentModel.Description("DT238")]
                T238,
            }
    
            //['dʒendə]
            [Flags]
            public enum EnumGender
            {
                None,
                [System.ComponentModel.Description("")]
                Male,
                [System.ComponentModel.Description("")]
                Female,
                Other,
            }
        }
    View Code

    3.辅助测试类TestHelper.cs

        public static class TestHelper
        {
            /// <summary>
            /// 执行一个方法并返回执行时间间隔
            /// </summary>
            public static TimeSpan InvokeAndGetTimeSpan(Action call)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                call();
                sw.Stop();
                return sw.Elapsed;
            }
    
            /// <summary>
            /// 执行一个方法并Console输出实际执行间隔(豪秒)
            /// </summary>
            [Conditional("DEBUG")]
            public static void InvokeAndWriteTimeSpan(Action call)
            {
                Console.WriteLine("TimeSpan:{0:N4}ms", InvokeAndGetTimeSpan(call).TotalMilliseconds);
            }
    
            /// <summary>
            /// 执行一个方法并返回托管内存使用大小(可能内存回收会导致不准确)
            /// </summary>
            public static long InvokeAndGetMemoryUsed(Action call)
            {
                var start = GC.GetTotalMemory(false);
                call();
                return GC.GetTotalMemory(false) - start;
            }
    
            /// <summary>
            /// 执行一个方法并Console输出托管内存使用大小(字节)
            /// </summary>
            [Conditional("DEBUG")]
            public static void InvokeAndWriteMemoryUsed(Action call)
            {
                Console.WriteLine("MemoryUsed:{0:N4}KB", InvokeAndGetMemoryUsed(call) / 1024F);
            }
    
            /// <summary>
            /// 执行一个方法并Console输出:实际执行间隔(豪秒);托管内存使用大小(可能内存回收会导致不准确)
            /// </summary>
            [Conditional("DEBUG")]
            public static void InvokeAndWriteAll(Action call)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                var start = GC.GetTotalMemory(false);
                call();
                var end = GC.GetTotalMemory(false);
                sw.Stop();
                Console.WriteLine("TimeSpan:{0:N4}ms", sw.ElapsedMilliseconds);
                Console.WriteLine("MemoryUsed:{0:N4}KB", (end - start) / 1024F);
                Console.WriteLine("CollectionCount(0):{0:N}", GC.CollectionCount(0));
            }
        }
    View Code
  • 相关阅读:
    数据库多表查询,左连接(入门)
    让弹出层始终显示在屏幕正中间
    jq中的ajax合集总结
    ajax之$.getScript()
    Jquery遮罩ShowLoading组件
    jquery中prop()方法和attr()方法的区别
    Bootstrap 响应式实用工具
    VS使用技巧
    ubuntu下postgreSQL安装配置
    基础设施即代码(Infrastructure as Code)
  • 原文地址:https://www.cnblogs.com/anding/p/5129178.html
Copyright © 2011-2022 走看看