一. 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();}});});}//输出结果:80TimeSpan:79,881.0000ms //共消耗了将近80秒MemoryUsed:-1,652.7970KBCollectionCount(0):7,990.00 //0代GC回收了7千多次,因为创建了大量的DescriptionAttribute对象
其中this.GetTestEnums();方法使用获取一个枚举值集合,用于测试的,集合大小80,执行100w次,相当于执行了8000w次GetDescriptionOriginal方法。
新闻热点
疑难解答
图片精选