做自己的ORMapping Framework ---- 第三讲 关于Attribute

在这个ORMapping的系列博文里,这个框架的实现会基于这个Attribute的使用。下面还是弄点东西,让小伙伴对Attribute这个东西有一个比较好的认识,我自己也就不写了,找一个写得还可以整理下的给大家了解下。

1、什么是Atrribute 
首先,我们肯定Attribute是一个类,下面是msdn文档对它的描述: 
公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。

在.NET中,Attribute被用来处理多种问题,比如序列化、程序的安全特征、防止即时编译器对程序代码进行优化从而代码容易调试等等。下面,我们先来看几个在.NET中标准的属性的使用,稍后我们再回过头来讨论Attribute这个类本身。(文中的代码使用C#编写,但同样适用所有基于.NET的所有语言)

3、Attribute类 
除了.NET提供的那些Attribute派生类之外,我们可以自定义我们自己的Attribute,所有自定义的Attribute必须从Attribute类派生。现在我们来看一下Attribute 类的细节:

protected Attribute(): 保护的构造器,只能被Attribute的派生类调用。

三个静态方法:

static Attribute GetCustomAttribute():这个方法有8种重载的版本,它被用来取出施加在类成员上指定类型的Attribute。

static Attribute[] GetCustomAttributes(): 这个方法有16种重载版本,用来取出施加在类成员上指定类型的Attribute数组。

static bool IsDefined():由八种重载版本,看是否指定类型的定制attribute被施加到类的成员上面。

实例方法:

bool IsDefaultAttribute(): 如果Attribute的值是默认的值,那么返回true。

bool Match():表明这个Attribute实例是否等于一个指定的对象。

公共属性: TypeId: 得到一个唯一的标识,这个标识被用来区分同一个Attribute的不同实例。

我们简单地介绍了Attribute类的方法和属性,还有一些是从object继承来的。这里就不列出来了。

下面介绍如何自定义一个Attribute: 自定义一个Attribute并不需要特别的知识,其实就和编写一个类差不多。自定义的Attribute必须直接或者间接地从Attribute这个类派生,如:

public MyCustomAttribute : Attribute { ... }

这里需要指出的是Attribute的命名规范,也就是你的Attribute的类名+"Attribute",当你的Attribute施加到一个程序的元素上的时候,编译器先查找你的Attribute的定义,如果没有找到,那么它就会查找“Attribute名称"+Attribute的定义。如果都没有找到,那么编译器就报错。

4、定义或控制特性的使用

对于一个自定义的Attribute,你可以通过AttributeUsage的Attribute来限定你的Attribute 所施加的元素的类型。代码形式如下: 
[AttriubteUsage(参数设置)] public 自定义Attribute : Attribute { ... }

作为参数的AttributeTarges的值允许通过“或”操作来进行多个值得组合,如果你没有指定参数,那么默认参数就是All 。 AttributeUsage除了继承Attribute 的方法和属性之外,还定义了以下三个属性:

AllowMultiple: 读取或者设置这个属性,表示是否可以对一个程序元素施加多个Attribute 。

Inherited:读取或者设置这个属性,表示是否施加的Attribute 可以被派生类继承或者重载。

ValidOn: 读取或者设置这个属性,指明Attribute 可以被施加的元素的类型。

下面让我们来做一些实际的东西。我们将会在Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。

隐藏行号 复制代码 ?这是一段程序代码。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]

public class HelpAttribute : Attribute

{

public HelpAttribute(String Description_in

{

this.description = Description_in;

}

protected String description;

public String Description

{

  get

{

return this.description;

}

}

}

代码讨论

  • 属性 AttributeUsage 指定该属性可以应用于的语言元素。
  • 属性类是从 System.Attribute 派生的公共类,至少有一个公共构造函数。
  • 属性类有两种类型的参数:
    • “定位参数”,每次使用属性时都必须指定这些参数。定位参数被指定为属性类的构造函数参数。在上面的示例中,url 便是一个定位参数。
    • “命名参数”,可选。如果使用属性时指定了命名参数,则必须使用参数的名称。通过包含非静态字段或属性来定义命名参数。在上面的示例中,Topic 便是一个命名参数。

先让我们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:

隐藏行号 复制代码 ?这是一段程序代码。

[Help("this is a do-nothing class")]//这里就可以正常使用

public class AnyClass

{

[Help("this is a do-nothing method")] //error 因为前面定义了不能标记在方法上

public void AnyMethod()

{

}

}

编译器报告错误如下:

AnyClass.cs: Attribute ‘Help‘ is not valid on this declaration type.

It is valid on ‘class‘ declarations only.

我们可以使用AttributeTargets.All来允许Help特性被放置在任何程序实体前。可能的值是:

Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface, 
Parameter,Delegate。

All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate,

ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface )

下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置多次。

隐藏行号 复制代码 ?这是一段程序代码。

[Help("this is a do-nothing class")]

[Help("it contains a do-nothing method")]

public class AnyClass

{

[Help("this is a do-nothing method")] //error

public void AnyMethod()

{

}

}

它产生了一个编译期错误。

AnyClass.cs: Duplicate ‘Help‘ attribute

Ok,现在我们来讨论一下最后的这个属性。Inherited, 表明当特性被放置在一个基类上时,它能否被派生类所继承。

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("BaseClass")]
    
  2. public class Base
    
  3. {
    
  4. }
    
  5. 
    
  6. public class Derive : Base
    
  7. {
    
  8. }
    

这里会有四种可能的组合:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]

第一种情况:

如果我们查询(Query)(稍后我们会看到如何在运行期查询一个类的特性)Derive类,我们将会发现Help特性并不存在,因为inherited属性被设置为false。

第二种情况:

和第一种情况相同,因为inherited也被设置为false。

第三种情况:

为了解释第三种和第四种情况,我们先来给派生类添加点代码:

隐藏行号 复制代码 ?这是一段程序代码。

  1. [Help("BaseClass")]
    
  2. public class Base
    
  3. {
    
  4. }
    
  5. 
    
  6. [Help("DeriveClass")]
    
  7. public class Derive : Base
    
  8. {
    
  9. }
    

现在我们来查询一下Help特性,我们只能得到派生类的属性,因为inherited被设置为true,但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。

第四种情况:

在这里,我们将会发现派生类既有基类的Help特性,也有自己的Help特性,因为AllowMultiple被设置为true。

通过反射访问属性

属性与程序元素关联后,可以使用反射查询属性存在及其值。查询属性的主要反射方法包含在 System.Reflection.MemberInfo 类(GetCustomAttributes 方法族)中。下面的示例演示使用反射获取对属性的访问的基本方法:

隐藏行号 复制代码 ?这是一段程序代码。

  1. System.Reflection.MemberInfo info = typeof(Help);
    
  2. object[] attributes = info.GetCustomAttributes(true);
    
  3. for (int i = 0; i < attributes.Length; i++)
    
  4. {
    
  5.     System.Console.WriteLine(attributes[i]);
    
  6. }
    

我们后面基本用到的也是这样,再深入点的也是一个道理,万变不离其宗,都一个道理。

时间: 2024-10-14 03:02:35

做自己的ORMapping Framework ---- 第三讲 关于Attribute的相关文章

做自己的ORMapping Framework ---- 第六讲 开始ORMapping之旅,ORMapping怎么说

这几天公司有点事情,没怎么来这边,现在来这边介绍下ORMapping实现一些什么东西 说到ORMapping,当然少不了的就是对数据库的增删查改,这边的类图我简单弄了下 下面的代码都是我在框架中的源码,这个编辑器很差,贴上来会有点难看,接口里的方法属性都是我平时开发中都会经常用到的,做什么的基本看名称就知道,这里还得说下,代码规范真的很重要,小朋友们写代码时候多注意点. public interface IEntityAccesser { bool Exist<T>(T obj); 存在监测

做自己的ORMapping Framework ---- 第九讲 开始ORMapping之旅,更新库表结构更新架构设计

做一个项目,没有人会把一个数据库设计得那么完善以至于后期不会有任何的改动,能设计这样数据库的人估计在火星上看你写代码吧. 不知道你们用过NH或者EF没?我用过之后,一到数据库结构发生变化的时候我就觉得很繁琐,什么类型变化,还有映射关系得改,更可怕的是要是你的代码写得比较乱的,那就麻烦了. 现在这些问题统统都没有了,接下来得在这个ORMapping的基础上讲一下这个DB的migration 操作了,我这边基本已经完善好了,先把这个类图给大家看看,后面我会介绍每个类是干什么用的,怎么用. 有兴趣的朋

做自己的ORMapping Framework ---- 第七讲 开始ORMapping之旅,ORMapping 中command怎么生成呢

上篇介绍了ORMapping的一个大体结构,看起来很简单,基本没有什么复杂的设计模式之说,关于接口类的实现与MEF的管理在上篇都介绍过,这篇就开始介绍ORMapping中的细节点了,当然还是围绕对数据库的操作(增删查改)来讲,我这就只介绍Insert command吧,其它的都一样. 有朋友就会问既然是ORMapping,那肯定得有一套完整的映射关于与操作逻辑,关于映射关系的介绍之前都简单介绍过了,比较抽象,现在在这里就以怎样生成Insert Command来介绍ORMapping的核心部分.

做自己的ORMapping Framework ---- 第二讲 准备工作

关于这个我也一直弄了好久,在有个项目中用过NH,用起来相当的不爽,代码很难维护,表结构不易更新,容易造成毁坏性结果,更特别的就是效率低下,据说新版的ADO.net EF好多了,期待吧. 在学习并实现一套ORMapping框架之前,我想小伙伴们得必须具备一定的C#基础,尤其是Attribute特性的熟悉,还要有一点Sqlserver 的基础,当然我这边就就sqlserver上实现,大多数软件开发人员最初估计也就是这样一个平台,所以在这上面实现比较方便,对于Oracle MySql的拓展,等这个弄完

Bot Framework的简单实现

最近微软发布了Bot Framework,查了一些资料后,也就自己尝试着写了一段代码.为了更方便开发,已经有人做了一个Bot Framework的开发模板,请到这里下载.下载完成后,将Bot Application.zip复制到"%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#"下,如下图 然后打开VS2015,这里在C#项目中可以找到Bot Application的模板,点击

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类.指定数据库连接字符串以及创建一个数据库.最后,我们还将添加视图和控制器来管理和显式产品和分类数据. 注意:如果你想按照本章的代码编写示例,你必须完成第一章或者直接从www.apress.com下载第一章的源代码. 2.1 添加模型类 Entity Framework的代码优先模式允许我们从模型类创

Entity Framework 6.0 Tutorials(10):Index Attribute

Index Attribute: Entity Framework 6 provides Index attribute to create Index on a particular column in the database as shown below: class Student { public Student() { } public int Student_ID { get; set; } public string StudentName { get; set; } [Inde

十四、C# 支持标准查询运算符的集合接口

支持标准查询运算符的集合接口. System.Linq.Enumeralbe类提供的一些常用的API 来执行集合处理 1.匿名类型 2.隐匿类型的局部变量 3.集合初始化器 4.集合 5.标准查询运算符 本章主要讨论泛型集合接口. 非泛型的集合类,待查. 一.匿名类型和隐式类型的局部变量声明 C#3.0增强. 1.匿名类型 一种特殊的数据类型,它最终是由编译器声明的,而非通过已定义好的类来声明的. 和匿名函数相似,当编译器看到一个匿名类型时,会自动执行一些后台操作,生成必要的代码, 允许像显式声

C#习题大全

C#习题大全 1.String str=new String("a")和String str = "a"有什么区别? String str = "a"; 这个只是一个引用,内存中如果有“a"的话,str就指向它,如果没有才创建如后还用到"a"这个字符串的话并且是这样用: String str1 = "a"; String str2 = "a"; String str2 = &q