溺水动物的C#学习笔记: 反射和特性(Reflection & Attribute)

溺水动物的C#学习笔记: 反射和特性(Reflection & Attribute)

  • 笔者是c#萌新, 如有错漏请指出.
  • 会更新(因为我完全没写懂..)

反射(Reflection)

假使我们现在要实现这样一个函数: 函数参数是Object,函数的功能就是执行这个类内所有参数为空的公有成员方法。那么显然, 我们需要运行时获取某个类中的所有成员方法. 反射为我们提供了可以这样做的工具.

您可以使用反射动态的(也就是在程序运行时)创建一个类型的实例, 绑定类型至现有的对象, 或是从现有对象中获取类型.

以下是一个反射利用GetType()的获知某个类型的信息的例子. 因为该方法是继承自Object类所以不需要using System.Reflection.

using System;
//using System.Reflection;

class Application {
    public static void Main(string[] args) {
        int i = 42;
        Type type = i.GetType();
        Console.WriteLine(type);
    }
}

运行结果如下.

System.Int32

以下是利用反射, 获取某个程序集(Assembly)的信息的例子:

using System;
using System.Reflection;

class Application {
    public static void Main(string[] args) {
        Assembly info = typeof(int).Assembly;
        Console.WriteLine(info);
    }
}

运行结果如下:

System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

特性(Attribute)

特性是一个强大的工具用以结合元数据, 或是声明信息.

所谓元数据(Metadata), 就是您在程序中定义的有关类型的信息. 所有基于.NET框架的程序都包含有一个元数据的集合, 用以描述定义在程序集里的类型和类型成员.

特性有如下的特质:

  • 特性会在您的程序里添加元数据. 您可以使用特性去找到元数据里您想要的信息.
  • 您可以为您的程序提供一个或者多个特性.
  • 特性可以像方法 (method) 和属性 (property) 那样接受参数 (arguments).
  • 您的程序可以访问自身的元数据, 也可以通过反射 (Reflection) 访问其他程序的元数据.

我觉得你可以简单的把这玩意理解成游戏里武器的附魔词缀, 比方说破旧的长剑什么的

在c#中, 您可以在中括号中写入特性的名称来声明特定的特性.

规定特性的语法如下:

[attribute(positional_parameters, name_parameter = value, ...)]
element

特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

在本例中, 可串行化的特性将在类中加入特定的元素.

[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

.NET框架提供了三种预定义特性, 分别是AttributeUsage, AttributeUsage, AttributeUsage.

AttributeUsage

您可以使用AttributeUsage来定义您自己的特性. 具体的内容将会在稍后提及.

它的语法如下:

[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]

其中:

  • 参数 validon 规定特性可被放置的语言元素。(语言元素就是诸如特性(property), 字段(field), 类(class)之类的). 它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
  • 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
  • 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)

请看如下的例子:

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]

这个特性可以修饰类, 构造函数, 字段, 属性, 方法. 它是多用的.

Conditional

语法如下:

[Conditional(
   conditionalSymbol
)]

这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符。它会引起方法调用的条件编译.

Obsolete

如果您更新了您代码中的某些部分, 但出于某种原因, 您仍然想保留旧的部分, 呢么您可以将旧的代码标记为Obsolete (过时的)

它的语法规则如下:

[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]

其中

  • 参数 message,是一个字符串,您可以在此处提供这个方法已经过时的信息, 并且可以告诉人们应该怎么做.
  • 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。

创建自定义特性

您也可以创建自定义的特性, 用于储存声明性质的信息. 其可以在运行时被检索.

创建并使用自定义特性包含如下四个步骤:

  • 声明自定义特性
  • 构建自定义特性
  • 在目标程序元素上应用自定义特性
  • 通过反射访问特性

声明自定义特性

一个新的自定义特性应派生自 System.Attribute 类。

如下是一个创建自定义特性DeBugInfo的语法.

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

构建自定义特性

我们继续完成我们声明的DeBugInfo特性. 假设我们希望它储存如下的信息:

  • bug 的代码编号
  • 辨认该 bug 的开发人员名字
  • 最后一次审查该代码的日期
  • 一个存储了开发人员标记的字符串消息

显然, 我们希望该特性必须包含前三种信息, 但可以选择是否包含后一种信息. 我们将我们的 DeBugInfo 类将带有三个用于存储前三个信息的私有属性和一个用于存储消息的公有属性。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位( positional)参数,消息将是一个可选的命名(named)参数。

具体语法示例如下:

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute
{
  private int bugNo;
  private string developer;
  private string lastReview;
  public string message;

  public DeBugInfo(int bg, string dev, string d)
  {
      this.bugNo = bg;
      this.developer = dev;
      this.lastReview = d;
  }

  public int BugNo
  {
      get
      {
          return bugNo;
      }
  }
  public string Developer
  {
      get
      {
          return developer;
      }
  }
  public string LastReview
  {
      get
      {
          return lastReview;
      }
  }
  public string Message
  {
      get
      {
          return message;
      }
      set
      {
          message = value;
      }
  }
}

应用自定义特性

您可以直接将您的自定义特性放在元素之前来应用他们. 如

 [DeBugInfo(55, "Zara Ali", "19/10/2012",
  Message = "Return type mismatch")]
  public double GetArea()
  {
      return length * width;
  }

您也可以利用反射来获得您自己定义的特性.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容