先明确一个概念:

元数据。.NET中元数据是指程序集中的命名空间、类、方法、属性等信息。这些信息是可以通过Reflection读取出来的。

再来看个例子:

#define BUG
//#define NOBUG
using System;
using System.Diagnostics; namespace AttributeExample
{
public static class AttributeTest
{
[Conditional("BUG")]
public static void OutputDebug(string msg)
{
Console.WriteLine(msg + " : bug");
} [Conditional("NOBUG")]
public static void OutputMessage(string msg)
{
Console.WriteLine(msg + " : no bug");
}
} class Program
{
static void Main(string[] args)
{
AttributeTest.OutputDebug("Function");
AttributeTest.OutputMessage("Function");
Console.Read();
}
}
}

运行结果:

将#define BUG注释掉,#define NOBUG的注释取消,重新运行的结果如下:

那么可以理解为,上述代码中的[Conditional()]起到了条件的作用。这就是一种特性。


特性是用于在运行时传递程序中各种元素(类、方法、结构、枚举等)的行为信息的声明性标签。可以通过使用特性向程序中添加声明性信息。这些信息添加到了元数据中。.NET框架中的特性包括Common AttributesCustom Attributes。其中Common Attributes包括Global Attributes, Obsolete Attributes, Conditional Attributes, Caller Info Attributes。

Common Attributes

  • Global Attributes 全局特性,应用于整个程序集。置于using后代码最上端。全局特性提供一个程序集的信息,分为三种类别:

    • Assembly identity attributes 程序集标识符特性。name, version, and culture这三个特性用于确定一个程序集的标识符。可以查看一下项目中Properties下面的AssemblyInfo.cs文件。
    • Informational attributes 信息特性,提供一些与公司或产品相关的信息,包括AssemblyProductAttribute,AssemblyTrademarkAttribute等。
    • Assembly manifest attributes 程序集清单特性。包括title, description, default alias, and configuration。
  • Conditional Attributes 标记了一个条件方法,其执行依赖于指定的预处理标识符(#define),实例就是上面那个。条件特性可以同时使用多个。比如[Conditional("A"), Conditional("B")]。
  • Obsolete Attributes 标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。其语法表示为:[Obsolete(message)]、[Obsolete(message, iserror)]

其中,message是一个string,描述项目为什么过时以及该替代使用什么;iserror是一个bool,如果为true,编译器应该把项目的使用当做一个错误,默认值是false,此时编译器生成一个警告。比如下面的例子:

using System;
using System.Diagnostics; namespace AttributeExample
{
class Program
{
[Obsolete("Don't use OldMethod, use NewMethod instead", true)]
static void OldMethod()
{
Console.WriteLine("It is the old method");
}
static void NewMethod()
{
Console.WriteLine("It is the new method");
} static void Main(string[] args)
{
OldMethod();
Console.Read();
}
}
}

这时程序无法编译,显示如下的错误:

  • Caller Info Attributes 通过使用该特性,可以获取调用某个方法的调用者的信息。比如代码的文件路径、代码的行等。比如下面所示的代码。
using System;
using System.Runtime.CompilerServices; namespace AttributeExample
{
class Program
{
public static void DoSomething()
{
TraceMessage("Something happened.");
} public static void TraceMessage(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Console.WriteLine("message: " + message);
Console.WriteLine("member name: " + memberName);
Console.WriteLine("source file path: " + sourceFilePath);
Console.WriteLine("source line number: " + sourceLineNumber);
} static void Main(string[] args)
{
DoSomething();
Console.Read();
}
}
}

运行结果如图所示:

Custom Attributes

.NET框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任务目标元素相关。创建并使用自定义特性包含四个步骤:

1. 声明自定义特性

 一个新的自定义特性应派生自System.Attribute类,比如:

   // 声明名为FirstAttribute的自定义特性 
  [AttributeUsage(AttributeTargets.Class, Inherited =false)]
class FirstAttribute : Attribute { }
  
  // 声明名为SecondAttribute的自定义特性
[AttributeUsage(AttributeTargets.Class)]
class SecondAttribute : Attribute { }

  // 声明名为ThirdAttribute的自定义特性
[AttributeUsage(AttributeTargets.Class, AllowMultiple =true)]
class ThirdAttribute : Attribute { }

又比如:

   // 声明名为CustomAttribute的自定义特性 
  [AttributeUsage(AttributeTargets.Class|
AttributeTargets.Constructor|
AttributeTargets.Field|
AttributeTargets.Method|
AttributeTargets.Property,
AllowMultiple =true)]
public class CustomAttributes : System.Attribute{}

2.构建自定义特性

上面已经声明了一个名为CustomAttribute的自定义特性,现在构建这个特性。该特性将存储调试程序获得的信息,包括:bug的代码编号、辨认该bug的开发人员名字、最后一次审查该代码的日期以及一个存储了开发人员标记的字符串消息。

CustomAttribute类将带有三个用于存储前三个信息的私有属性和一个用于存储消息的公有属性。因此bug编号、开发人员名字和审查日期将是CustomAttribute类的必需的定位(positional)参数,消息将是一个可选的命名(named)参数。每个特性必须至少有一个构造函数。必需的定位参数应通过构造函数传递,如下面的代码所示:

    [AttributeUsage(AttributeTargets.Class|
AttributeTargets.Constructor|
AttributeTargets.Field|
AttributeTargets.Method|
AttributeTargets.Property,
AllowMultiple =true)]
public class CustomAttributes : System.Attribute
{
public int BugNo { get; }
public string Developer { get; }
public string LastReview { get; }
public string Message { get; set; } public CustomAttributes(int BugNo, string Developer, string LastReview)
{
this.BugNo = BugNo;
this.Developer = Developer;
this.LastReview = LastReview;
}
}

3.在目标程序元素上应用自定义特性

通过把特性放置在紧接着它的目标之前,来应用该特性:

    [CustomAttributes(45,"Zara Ali","12/8/2012", Message ="Return type mismatch")]
[CustomAttributes(49,"Nuha Ali","10/10/2012",Message ="Unused variable")]
class Rectangle
{
protected double length;
protected double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
} [CustomAttributes(55,"Zara Ali","19/10/2012", Message ="Return type mismatch")]
public double GetArea()
{
return length * width;
} [CustomAttributes(56,"Zara Ali", "19/10/2012")]
public void Display()
{
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}

4.通过反射访问特性

别忘了使用using System.Reflection;

class ExecuteRectangle
{
static void Main(string[] args)
{
Rectangle r = new Rectangle(4.5, 7.5);
r.Display();
object[] attrs = r.GetType().GetCustomAttributes(false);
// 遍历Rectangle类的特性
foreach(Attribute attr in attrs)
{
CustomAttributes attribute = (CustomAttributes)attr;
if(null != attribute)
{
Console.WriteLine("Bug no: {0}", attribute.BugNo);
Console.WriteLine("Developor: {0}", attribute.Developer);
Console.WriteLine("Last Reviewed: {0}", attribute.LastReview);
Console.WriteLine("Remarks: {0}", attribute.Message);
}
} // 遍历方法特性
object[] methods = r.GetType().GetMethods();
foreach(MethodInfo method in methods)
{
foreach(object attribute in method.GetCustomAttributes(true))
{
CustomAttributes attr = attribute as CustomAttributes;
if(null != attr)
{
Console.WriteLine("Bug no: {0}, for Method: {1}", attr.BugNo, method.Name);
Console.WriteLine("Developer: {0}", attr.Developer);
Console.WriteLine("Last Reviewed: {0}", attr.LastReview);
Console.WriteLine("Remarks: {0}", attr.Message);
}
}
}
Console.Read();
}
}

运行结果如图所示:

参考文献:

1.https://www.runoob.com/csharp/csharp-attribute.html

2.https://www.runoob.com/csharp/csharp-reflection.html

3.https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/

4.https://blog.csdn.net/xiaouncle/article/details/70216951

C#特性(属性)Attribute的更多相关文章

  1. JavaScript特性(attribute)、属性(property)和样式(style)

    最近在研读一本巨著<JavaScript忍者秘籍>,里面有一篇文章提到了这3个概念. 书中的源码可以在此下载.我将源码放到了线上,如果不想下载,可以直接访问在线网址,修改页面名就能访问到相 ...

  2. js便签笔记(2)——DOM元素的特性(Attribute)和属性(Property)

    1.介绍: 上篇js便签笔记http://www.cnblogs.com/wangfupeng1988/p/3626300.html最后提到了dom元素的Attribute和Property,本文简单 ...

  3. ASP.NET Web API 2.0新特性:Attribute Routing1

    ASP.NET Web API 2.0新特性:Attribute Routing[上篇] 对于一个针对ASP.NET Web API的调用请求来说,请求的URL和对应的HTTP方法的组合最终决定了目标 ...

  4. Unity3D编辑器扩展(五)——常用特性(Attribute)以及Selection类

    前面写了四篇关于编辑器的: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 Unity3D ...

  5. 特性(attribute)

    一.什么是特性? 特性(attribute)是被指定给某一声明的一则附加的声明性信息. 在C#中,有一个小的预定义特性集合.在学习如何建立我们自己的定制特性(custom attributes)之前, ...

  6. C#提高--------------获取方法返回值的自定义特性(Attribute)

    .NET(C#):获取方法返回值的自定义特性(Attribute) 转载 2013年05月08日 10:54:42 1456 来自:http://www.cnblogs.com/mgen/archiv ...

  7. C# 特性(Attribute)

    C# 特性(Attribute) 特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签.您可以通过使用特性向程序添加声明性信息.一个声明 ...

  8. NET 特性(Attribute)

    NET 特性(Attribute) 转自 博客园(Fish) 特性(Attribute):是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签. 您可以通过使用特 ...

  9. 【Unity|C#】基础篇(13)——特性(Attribute)

    [学习资料] <C#图解教程>(第24章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  10. 特性节点Attribute

    深入理解DOM节点类型第六篇——特性节点Attribute document.getElementById('b_results').attributes[0].textContent documen ...

随机推荐

  1. 学习AJAX必知必会(4)~JQuery发送Ajax请求

    一.JQuery发送Ajax请求 ■ 对于get和post请求,jQuery内部封装了Ajax请求的4个步骤和数据格式的设置 ■ 对于Ajax通用请求,jQuery内部封装了Ajax请求的4个步骤和数 ...

  2. WPF学习笔记(四):AvalonEdit 代码高亮编辑控件专题

    AvalonEdit 是一个基于 WPF 的文本编辑器组件.它是由 Daniel Grunwald 为 SharpDevelop 编写的.从 5.0 版开始,AvalonEdit 根据MIT许可证发布 ...

  3. gorm概述与快速入门

    特性 全功能 ORM 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承) Create,Save,Update,Delete,Find 中钩子方 ...

  4. .Net Api 之如何使用Elasticsearch存储文档

    .Net Api 之如何使用Elasticsearch存储文档 什么是Elasticsearch? Elasticsearch 是一个分布式.高扩展.高实时的搜索与数据分析引擎.它能很方便的使大量数据 ...

  5. nginx二进制安装

    目录 一:二进制安装nginx 1.下载CentOS源 2.安装CentOS源 3.下载epel源(失败显示未找到命令) 4.解决依赖 5.安装Epel源 6.安装nginx 一:二进制安装nginx ...

  6. linux解析映射文件与自动加载脚本

    目录 一 :解析映射文件 1.解析文件的由来之主机名: 2.解析映射文件(DNS) 二:磁盘挂载文件 三:开机自动加载脚本 一 :解析映射文件 1.解析文件的由来之主机名: 无论是在局域网还是在INT ...

  7. java中的继承 和多态。

    package com.aaa.zxf.ajax.test; /** *一. java 中的继承和多态. * * 继承的特性? * 1.实现继承的方式 * A 如何建立继承关系(一个类继承于 另一个类 ...

  8. vector概述

    vector是一个能够支持任何类型的容器,本身为一个可以动态增长的数组. 1.vector基本数据结构 STL中所有的容器都包括三部分: 迭代器,遍历容器的元素,控制容器空间的边界和元素移动. 构造函 ...

  9. Java8特性大全(最新版)

    一.序言 Java8 是一个里程碑式的版本,凭借如下新特性,让人对其赞不绝口. Lambda 表达式给代码构建带来了全新的风格和能力: Steam API 丰富了集合操作,拓展了集合的能力: 新日期时 ...

  10. 布客&#183;ApacheCN 编程/大数据/数据科学/人工智能学习资源 2020.4

    公告 我们的机器学习群(915394271)正式改名为财务提升群,望悉知. 请关注我们的公众号"ApacheCN",回复"教程/路线/比赛/报告/技术书/课程/轻小说/漫 ...