当前位置: 首页 > news >正文

上海营销型网站开发宁波网络优化seo

上海营销型网站开发,宁波网络优化seo,中国矿井建设相关媒体网站,济南赢动网站建设Attribute是.NET平台上提供的一种元编程能力,可以通过标记的方式来修饰各种成员。无论是组件设计,语言之间互通,还是最普通的框架使用,现在已经都离不开Attribute了。迫于Attribute的功能的重要性(Kent Beck认为NUnit比…

Attribute是.NET平台上提供的一种元编程能力,可以通过标记的方式来修饰各种成员。无论是组件设计,语言之间互通,还是最普通的框架使用,现在已经都离不开Attribute了。迫于Attribute的功能的重要性(Kent Beck认为NUnit比早期JUnit设计的好,一个主要方面便是利用了Attribute),Java语言也在5.0版本中引入了与Attribute类似的Annotation概念。不过Attribute说到底也是一种反射操作,平时正常使用不会带来问题,但是密集的调用还是对性能有一定影响的。这次我们就来总结看看我们究竟可以如何回避Attribute操作的一些性能问题。

假设我们有一个Attribute,它定义在一个类型上:

[AttributeUsage(AttributeTargets.Class,AllowMultiple = true,Inherited = true)]
public class TestAttribute : Attribute
{public TestAttribute(string prop){this.Prop = prop;}public TestAttribute() { }public string Prop { get; set; }
}[Test("Hello World")]
[Test(Prop = "Hello World")]
public class SomeClass { }

那么,如果我们需要获得SomeClass类型上所标记的TestAttribute,我们一般会使用Type对象的GetCustomAttributes方法。那么在其中又发生了什么呢?

通过.NET Reflector来追踪其中实现,会发现这些逻辑最终是由CustomAttribute的GetCustomAttributes方法完成的,感兴趣的朋友们可以找到那个最复杂的重载。由于实现有些复杂,我没有看懂完整的逻辑,但从关键的代码上可以看出,它其实是使用了Activator.CreateInstance方法创建对象,并且使用反射对Attribute对象的属性进行设置。于是我便打算了解一下这些反射操作占整个GetCustomAttributes方法的多大比重:

CodeTimer.Time("GetCustomAttributes", 1000 * 100, () =>
{var attributes = typeof(SomeClass).GetCustomAttributes(typeof(TestAttribute), true);
});CodeTimer.Time("Reflection", 1000 * 100, () =>
{var a1 = (TestAttribute)Activator.CreateInstance(typeof(TestAttribute), "Hello World");var a2 = (TestAttribute)Activator.CreateInstance(typeof(TestAttribute));typeof(TestAttribute).GetProperty("Prop").SetValue(a2, "Hello World", null);
});

结果如下:

GetCustomAttributes
        Time Elapsed:   2,091msCPU Cycles:     5,032,765,488Gen 0:          43Gen 1:          0Gen 2:          0Reflection
        Time Elapsed:   527msCPU Cycles:     1,269,399,624Gen 0:          40Gen 1:          0Gen 2:          0

可以看出,虽然GetCustomAttributes方法中使用了反射进行对象的创建和属性设置,但是它的大部分开销还是用于获取一些元数据的,它们占据了3/4的时间,而反射的开销其实只占了1/4左右。这就有些令人奇怪了,既然是静态的元数据,为什么.NET Framework不对这些数据进行缓存,而是每次再去取一次呢?即便是我们不应该缓存最后得到的Attribute对象,但是用于构造对象的“信息”是完全可以缓存下来的。

事实上.NET Framework事实上已经给出了足够的信息,那便是CustomAttributeData的GetCustomAttributes方法,它返回的是IList<CustomAttributeData>对象,其中包含了构造Attribute所需要的全部信息。换句话说,我完全可以根据一个CustomAttributeData来“快速构建”Attribute对象:

public class AttributeFactory
{public AttributeFactory(CustomAttributeData data){this.Data = data;var ctorInvoker = new ConstructorInvoker(data.Constructor);var ctorArgs = data.ConstructorArguments.Select(a => a.Value).ToArray();this.m_attributeCreator = () => ctorInvoker.Invoke(ctorArgs);this.m_propertySetters = new List<Action<object>>();foreach (var arg in data.NamedArguments){var property = (PropertyInfo)arg.MemberInfo;var propertyAccessor = new PropertyAccessor(property);var value = arg.TypedValue.Value;this.m_propertySetters.Add(o => propertyAccessor.SetValue(o, value));}}public CustomAttributeData Data { get; private set; }private Func<object> m_attributeCreator;private List<Action<object>> m_propertySetters;public Attribute Create(){var attribute = this.m_attributeCreator();foreach (var setter in this.m_propertySetters){setter(attribute);}return (Attribute)attribute;}
}

AttributeFactory利用了FastReflectionLib,将ConstructorInfo和PropertyInfo封装成性能很高的ConstructorInvoker和PropertyAccessor对象,这样使用起来便有数量级的性能提高。我们再来进行一番测试:

var factories = CustomAttributeData.GetCustomAttributes(typeof(SomeClass)).Where(d => d.Constructor.DeclaringType == typeof(TestAttribute)).Select(d => new AttributeFactory(d)).ToList();CodeTimer.Time("GetCustomAttributes", 1000 * 100, () =>
{var attributes = typeof(SomeClass).GetCustomAttributes(typeof(TestAttribute), true);
});CodeTimer.Time("AttributeFactory", 1000 * 100, () => factories.ForEach(f => f.Create()));

结果如下:

GetCustomAttributesTime Elapsed:   2,131msCPU Cycles:     5,136,848,904Gen 0:          43Gen 1:          43Gen 2:          0Attribute FactoryTime Elapsed:   18msCPU Cycles:     44,235,564Gen 0:          4Gen 1:          4Gen 2:          0

在这里,我们先获得SomeClass中所有定义过的CustomAttributeData对象,然后根据其Constructor的类型来判断哪些是用于构造TestAttribute对象的,然后用它们来构造AttributeFactory。在实际使用过程中,AttributeFactory实例可以缓存下来,并反复使用。这样的话,我们即可以每次得到新的Attribute对象,又可以避免GetCustomAttributes方法所带来的莫名其妙的开销。

事实上,我们完全可以利用这个方法,来实现一个性能更高的GetCustomAttributesEx方法,它的行为可以和.NET自带的GetCustomAttributes完全一致,但是性能可以快上无数——可能是100倍。不过,这个方法虽然不难编写,但比较麻烦。因为CustomAttributeData只能用于获得“直接定义”在某个成员上的数据,而实际情况是,我们往往还必须根据某个Attribute上标记的AttributeUsage的AllowMultiple和Inherited属性来决定是否要遍历整个继承链。只有这般,我们才能百分之百地重现GetCustomAttribute方法的行为。

不过我们在这里有个优势,那便是“静态”。一旦“静态”,我们便可以为某个特定的场景,用“肉眼”判断出特定的处理方式,这样便不需要一个非常通用的GetCustomAttributeEx方法了。例如在实际使用过程中,我们可以可以发现某个Attribute的Inherited属性为false,那么我们便可以免去遍历继承链的麻烦。

最后还有两点可能值得一提:

除了Type,Assembly等成员自带的GetCustomAttributes方法之外,Attribute类也有些静态GetCustomAttributes方法可用于获取Attribute对象。但是,通过.NET Reflector,我们可以发现,Attribute类中的静态方法,最终还是委托给各自的实例方法,因此不会有性能提高。唯一区别对待的是ParameterInfo——不过我没搞懂为什么那么复杂,感兴趣的朋友可以自行探索一番。

如果仅仅是判断一个成员是否定义了某个特定类型的Attribute对象,那么可以使用Attribute.IsDefined静态方法。它的性能比GetCustomAttributes后再判断数组的Length要高效许多倍。不过个人认为这点倒并不是非常重要,因为这原本就是个静态的信息,即便是我们使用较慢的GetCustomAttributes方法来进行判断,也可以把最终的true或false结果进行缓存,这自然也不会有性能问题了。

我们之所以要反复调用GetCustomAttributes方法,就是因为每次得到的Attribute对象都是新建的,因此在某些场景下可能无法缓存它们。不过现在已经有了现在更快的做法,在这方面自然也就不会有太大问题了。

转载于:https://www.cnblogs.com/1175429393wljblog/p/5524316.html

http://www.lbrq.cn/news/2357983.html

相关文章:

  • 蓝田网站建设定制网站建设电话
  • 遂昌赶街网站百度推广关键词排名在哪看
  • 企业网站建设解决方案 成都网站关键词优化的价格
  • 宝山网站建设宝山汕头网站建设方案外包
  • win7如何建设免费网站网络公司网页设计
  • 学校网站建设讯息软文广告例子
  • 淘宝宝贝链接怎么做相关网站磁力搜索引擎不死鸟
  • 作一手房用什么做网站百度站长提交
  • 备案域名做的网站别人用来诈骗福州百度分公司
  • 毕业设计做购物网站的要求发布新闻
  • 如何做优品快报下的子网站app安装下载
  • 免费网站建设 百度收录免费b站推广软件
  • 福田做网站的网站关键词优化排名怎么做
  • 公司注册网上核名用哪个方式注册seo学习网站
  • 网站建设经验与团队外贸推广引流
  • 苏州品牌网站设计seo教程搜索引擎优化入门与进阶
  • 在越南做网站都是什么人免费网站流量统计工具
  • 做企业评价的有哪些网站最近一周新闻大事摘抄2022年
  • 做巧克力的网站产品seo是什么意思
  • 潍坊网站建设服务好用的搜索引擎
  • 免费给人做网站的海城seo网站排名优化推广
  • 青岛做网站企业自动搜索关键词软件
  • 深圳网站建设怎样做郑州网络推广培训
  • 网站的模板演示怎么做google推广费用
  • 做电影网站考什么杭州网站优化企业
  • 如何做网站给女朋友河南网站推广优化
  • 北京建设局网站首页公司网站排名
  • 网站设计是用ps做图吗网站推广的内容
  • 做网站销售提成怎么算营销型网站的类型
  • 重庆市建设工程信息网站诚信分独立网站和平台网站
  • watermark的作用
  • github上传大文件(多种解决方案)
  • UDP和TCP的主要区别是什么?
  • 【RTSP从零实践】13、TCP传输AAC格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)
  • 【AI智能体】Dify 基于知识库搭建智能客服问答应用详解
  • vscode连接不上云服务解决