1、Attributes语义学

程序语言经历多次革命,多重继承渐渐消失于近代程序语言中,其空下的位置也正式由接口(Interface)所取代。另一方面,对象持久机制也慢慢成为程序语言的基本建设之一,不过目前出现一个诡异的现象,在java语言中,类要支持Serilization就必须声明成如下形式:

public class ClassA implements java.io.Serializable

有趣的是,Serializable界面中并未声明任何须实现的函数,纯粹只是一个空接口,这一点似乎不太符合接口的正常用法。的确,Serializable被当成是识别证使用,.NET Framework中此类运用被明确分割成另一种机制,它的名称叫Attribute。Attribute的出现是为了由接口或抽象类中分离出标签类型的运行,例如java.io.Serializable是一个接口,但其真正的用途却是为此类贴上一个标签,代表着此类支持Serializable能力。Serializable界面在.NET Framework则被正名为SerializableAttribute,相较两者,.NET Framework在语意上似乎显得明确许多。笔者喜欢将Attribute成之为标签(便利贴,如果你觉得亲切的话),因为它可以贴在类、方法、属性、成员变量之上,告知处理者应该何如处理目标物。此处须特别澄清一点,Attribute本身是被动物,简单地说是其自身不可能知道贴在哪一个目标上,所以中Attribute中是无法存取目标物的。

2、看看Attribute能做什么

用户预定义的Attribute必须继承自System.Attribute类,其构造函数所接受的参数代表着使用该Attribute时所须传入的参数,程序1-1是一个简单的Attribute范例。

using System;
using System.ComponentModel;
namespace AttributeFullDemo
{
[AttributeUsage(AttributeTargets.Class,Inherited=false,AllowMultiple=false)]
public class ClassShowProcessAttribute:Attribute
{
private bool show = false;
public bool Show
{
get{
return show;
}
}
public ClassShowProcessAttribute(bool show)
{
this.show = show;
}
}
}

有趣的是用户预定义的Attribute本身也贴上了另一个Attribute,不过这在语意上并不冲突,AttributeUsage代表着此Attribute所适用的情况,其第一个参数是该Attribute所使用的范围,其可以是类、方法、属性等等;第二个参数代表着当Attribute被贴在目标物上后,继承至目标物的继承者是否会连此Attribute一并继承;第三个参数代表此Attribute是否允许重复贴在同一目标物上,意思是说是否允许同时贴两个以上同样的Attribute在目标物上。基本上Attribute是绑定于Type上,设计人员得通过Type.GetCustomAttributes函数来判定此Type中拥有哪些Attribute,程序1-2、1-3是使用ClassShowProcessAttribute的范例。

1-2:贴上ClassShowProcessAttribute的类范例

using System;
namespce AttributeFullDemo
{
[ClassShowProcess(true)]
public class AttrClassTest
{
public AttrClassTest(){}
}
}

1-3: 使用贴上ClassShowProcessAttribute类的范例

private void btnTestClass_Click(object sender,System.EventArgs e)
{
object[] o = new object[]{
new AttrClassTest(),
new AttrClassTest(),"TEST"
};
foreach(object item in o)
{
ClassShowProcessAttribute[] attr=
(ClassShowProcessAttribute[])item.GetType().GetCustomAttributes(typeof(ClassShowProcessAttribute),false);
if(attr.Length!=0)
if(attr[0].Show)
textBox1.Text +="\r\n" + item.ToString();
}
}

程序1-3中创建了一个object类型的数组,在其中放入了两个AttrClassTest对象及一个string对象,接着遍历此对象数组一一调用Type.GetCustomAttributes函数,GetCustomAttributes函数拥有两个重载函数,其中之一接受inherited参数,此参数对应至AttributeUsage的inherited参数。另一个则接受inherited及一个Type参数,此处使用的是第二个重载函数,并指定其Type为ClassShowProcessAttribute,这可以使返回值仅限于此Attribute。此处有一点须特别注意,Attribute对象的创建时机是设计者调用GetCustomAttributes函数时其拥有的两个重载函数代表两种创建方式,第一种方式会创建该Type的所有Attributes对象,除非有特殊需求,否则设计人员应该尽量使用第二种,减少创建无意义的Attribute对象。

Attribute in Member Field

除了绑定至类外,Attribute也可以绑定至成员变量上,程序2-1,程序2-2展现了此种应用:

2-1 可绑定至成员变量上的Attribute范例

using System;
using System.ComponentModel;
using System.Reflection;
namespace AttributeFullDemo
{
public interface IFiledShow
{
string Show(object o);
}
[AttributeUsage(AttributeTargets.File|AttributeTargets.Property,Inherited=false,AllowMultiple=false)]
public class FiledShowAttribute:Attribute
{
private bool show = false;
private Type showClass =null;
public bool Show
{
get
{
return show;
}
}
public Type ShowClass
{
get{
return showClass;
}
}
public IFileShow CreateShowInstance()
{
object o;
ConstructorInfo cinfo = showClass.GetConstructor(new Type[]{});
o = cinfo.Invoke(null);
return (IFileShow)o;
}
public FiledShowAttribute(bool show,Type showClass)
{
show = show;
showClass = showClass;
if(showClass==null)
{
throw new Exception("must provides showClass!!");
}
}
}
}

2-1 贴上FiledShowAttribute的类范例

using System;
using System.ComponentModel;
namespace AttributeFullDemo
{
public IFiledShow.Show(object o)
{
return o.ToString();
}
}
public class AttrFiledTest
{
[FiledShow(true,Typeof(StringFiledShow))]
public int number =0;
public AttrFiledTest()
{
}
}

此程序也展现了另一种Attribute类型的应用,它接受一个Type参数,这代表着设计人员于是用此Attribute时可以指定一个自定义的Type来改变其显示的行为,设计人员也可以提供一系列的预先定义的Type供用户运用,这将Attribute带往另一个较为复杂且高扩展性的应用面,程序2-4的范例展示了这一点。
 2-4 是用贴上FiledShowAttribute类的范例

private void btnTestFileld_Click(object sender,System.Events e)
{
AttrFiledTest[] o = new AttrFiledTest[]{ new AttrFieldTest(),new AttrFieldTest()};
o[0].number =15;
o[1].number=30;
foreach(AttrFiledTest item in o)
{
FiledShowAttribute[] fattr=(FieldShowAttribute[])field.GetCustomAttributes(typeof(FieldShowAttribute),false);
if(fattr.Length!=0)
{
textBox1.Text +="\r\n" + field.Name + " =" + fattr[0].CreateShowInstance().Show(field.GetValue(item));
}
}
}

这种概念是将原本应该有由是用端处理的工作交由另一个类来处理,这可以有效地切割应用程序,给予较高的扩展性及明确的定位。不过此范例并不是一个良好的设计,因为其在寻找Attribute时会为每一个Attribute.Type创建一个实体,因而有滥用内存之嫌。要改善这一点,设计人员可以于Attribute中预定义一个静态函数,并要求传入的Attribute.Type类型必须拥有一个静态函数,程序2-5和2-6是修改后的范例。

2-5 修改后的FieldShowAttribute范例

using System;
using System.ComponentModel;
using System.Reflection;
namespace AttributeFullDemo
{
public interface IFieldShow
{
string Show(object o);
}
[AttributeUsage(AttributeTargets.Field|AttributeTargets.Property,Inherited=false,AllowMultiple=false)]
public class FieldShowAttribute:Attribute
{
private bool show =false;
private Type showClass =null;
public bool Show
{
get{
return show;
}
}
public Type ShowClass
{
get{
return showClass;
}
}
public IFieldShow CreateShowInstance()
{
object o;
ConstructorInfo cinfo = showClass.GetConstructor(new Type[]{});
o = cinfo.Invoke(null);
return (IFieldShow)o;
}
public static string ShowValue(FieldShowAttribute attr,object o,FieldInfo valueObject)
{
MethodInfo mi = attr.ShowClass.GetMothod("Show",BindingFlags.Static|BindingFlags.Public);
return (string)mi.Invoke(null,new object[] {valueObject.GetValue(o)});
}
public FieldShowAttribute(bool show ,Type showClass)
{
show =show;
showClass = showClass;
if(showClass==null) throw new Exception("must provides showClass!!");
}
}
}

2-6 修改后贴上FieldShowAttribute类的范例

using System;
using System.ComponentModel;
namespace AttributeFullDemo
{
public class StringFieldShow:IFieldShow
{
string IFieldShow.Show(object o)
{
return o.ToString();
}
}
public class StringFieldShow2
{
public static string Show(object o)
{
return o.ToString();
}
}
public class AttrFieldTest
{
[FieldShow(true,typeof(StringFieldShow2))]
public int number=0;
public AttrFieldTest(){}
}
}

此范例使用了静态函数及Reflection技术来实现前面所提及的想法,现在使用端的范例就不需要为每一个Attribute创建一个ShowClass对象了,见下面程序2-7

2-7 使用贴上FieldShowAttribute类的范例

private void btnTestField_Click(object sender,System.EventArgs e)
{
AttrFileTest[] o new AttrFieldTest[] {new AttrFieldTest(), new AttrFieldTest()};
o[0].number =15;
o[1].number =16;
foreach(AttrFieldTest item in o)
{
foreach(Field field in item.GetType().GetFields())
{
FieldShowAttribute[] fattr=
(FieldShowAttribute[])field.GetCustomAttributes(typeof(FieldShowAttribte),false);
if(fattr.Length !=0)
textBox1.Test+= "\r\n" + FieldShowAttribute.ShowValue(fattr[0],item,field);
}
}
}

Attributes特性相关推荐

  1. Asp.net MVC 4 Attributes特性

    Attributes特性 ActionFilterAttribute Represents the base class for filter attributes. 代表筛选器属性的基类. Acti ...

  2. 单元测试框架NUnit 之 Attributes特性(一)

    最早的时候,Nunit使用继承和命名约定来确认方法或类是用来测试的.但从2.0开始,开始使用了自定义特性custom attributes:这样你不必继承一个特定的类,可以自由的规定类的层次:没有了命 ...

  3. XAML实例教程系列 – 对象和属性

    在前一篇已经介绍XAML概念:"XAML语言是Extensible Application Markup Language的简称,英文发音是"zammel",中文称为&q ...

  4. Win10系列:UWP界面布局基础4

    类型转换 前面讲到过,在定义元素时可以通过Attributes特性方式为其设置属性并为属性赋值,在实际开发中所赋予的值可能和属性本身的数据类型不相符,这时XAML解析器就会使用类型转换器(Type C ...

  5. 深入理解JavaScript系列(18):面向对象编程之ECMAScript实现

    http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html 介绍 本章是关于ECMAScript面向对象实现的第2篇,第1篇我们讨论的是概 ...

  6. android中的so加固,so加固-加密特定section中的内容

    Android逆向之旅-基于对so中的section加密技术实现so加固 这篇文章写得真心好,建议先阅读一下原著,这里只是自己的实践过程(纸上得来终觉浅,绝知此事要躬行),和一些更细节的解释罢了. 一 ...

  7. OpenSolaris/Solaris中文FAQ

    本文转载于 http://blog.chinaunix.net/uid-11193716-id-2896321.html OpenSolaris/Solaris中文FAQ (2008-08-04 19 ...

  8. OpenSolaris/Solaris 常见问题解答

    本文转载于 http://blog.chinaunix.net/uid-11193716-id-2896321.html OpenSolaris/Solaris中文FAQ (2008-08-04 19 ...

  9. [ASP.NET MVC 小牛之路]02 - C#知识点提要

    特别提醒:本文编写时间是 2013 年,请根据目前 .NET 发展接收你所需的知识点. 本篇博文主要对asp.net mvc开发需要撑握的C#语言知识点进行简单回顾,尤其是C# 3.0才有的一些C#语 ...

最新文章

  1. 《Android应用开发入门经典(第3版)》——第6.1节创建演示应用
  2. python解析xml提交到hdfs_完美解决python针对hdfs上传和下载的问题
  3. 赛题出简单了,让我们情何以堪?
  4. CentOS6.5+puppet3.7.3 安装、配置及测试
  5. python知识:用turtle绘制樱桃树
  6. Django框架搭建
  7. 【Java】浅析SimpleDateFormat类
  8. 用Python写一个滑动验证码
  9. python中对象和类的关系_Python面向对象之类与类之间的关系
  10. 子程序入口参数是什么_三菱FX PLC | 什么是中断服务?没事多看几遍
  11. stcc52单片机时钟电路_有备无患,单片机面试问题集
  12. linux安装中文输入法sc,Ubuntu 设置中文输入法
  13. iPad 2 移植 Siri 常见问题解答及注意事项
  14. 史上最全的美国留学资料,从此不用找中介
  15. 星广互动推出全球首个智能AR广告平台 重塑UGC视频广告价值
  16. 关于MD5码的一些自我总结
  17. 我和数据类型抗争的血泪史(二十五分钟)
  18. Opencv入门第一课打开窗口
  19. 服务器主板准系统怎么拆,主板准系统及电源装箱步骤完成_技嘉 GA-B85M-D3V_主板评测-中关村在线...
  20. GSM和GPRS网络原理的基本思路

热门文章

  1. 计算机专业求职信英语,计算机专业的英语求职信
  2. android驱动开发工程师,android驱动开发工程师
  3. bzoj 4237: 稻草人
  4. oracle 排版,oracle中查看信息的时候修改它的排版相当的麻烦!
  5. 迪杰斯特拉算法c语言6,C语言迪杰斯特拉实现最短路径算法.doc
  6. idea 打 jar 包,包含第三方 jar 包
  7. Think it over……好好想想……
  8. 什么显卡是个人计算机主流,主流显卡
  9. 618买电视还是投影仪,这款投影仪有4重好礼等着你
  10. 根据周数获取当周的起始日期