C#自定义属性与反射综合应用

简介: 一、属性的基本概念 1、什么是属性?为什么要使用属性?     属性提供功能强大的方法以将声明信息与 C# 代码(类型、方法、属性等)相关联。特别在数据库设计中,一个数据库中的各个字段的性质不一样,有的是primary key,有的是key,有的则是普通的字段,通过属性的该表的类中进行字段标识,使用时通过反射出这些属性就可以知道这个字段的信息。

一、属性的基本概念

1、什么是属性?为什么要使用属性?

    属性提供功能强大的方法以将声明信息与 C# 代码(类型、方法、属性等)相关联。特别在数据库设计中,一个数据库中的各个字段的性质不一样,有的是primary key,有的是key,有的则是普通的字段,通过属性的该表的类中进行字段标识,使用时通过反射出这些属性就可以知道这个字段的信息。

2、属性的两种表现形式

    一种是在公共语言运行时 (CLR) 中定义的属性。
    另一种是可以创建的用于向代码中添加附加信息的自定义属性。此信息可在以后以编程方式检索。

3、属性的使用场合

    属性可以放置在几乎所有的声明中(但特定的属性可能限制在其上有效的声明类型)。

4、属性的使用语法

    在语法上,属性的指定方法为:将括在方括号中的属性名置于其适用的实体声明之前。

二、属性的案例说明

    本案例主要实现自定义属性类DescriptionAttribute,在类CNBAStar及其成员中应用该属性,并在main()中通过反射的方式将这些属性获取。
案例代码:

点击(此处)折叠或打开

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;

  6. namespace CustomAttibute2
  7. {
  8.     class Program
  9.     {
  10.         [Description("I'm class CNBAStar ",ExtraInfo="private")]
  11.         class CNBAStar
  12.         {
  13.             private string mName = "Michael Jordan";

  14.             #region Properties field
  15.             [Description("I'm CNBAStar's attribute Name")]
  16.             public string Name
  17.             {
  18.                 get { return mName; }
  19.                 set { Name = mName; }
  20.             }
  21.             #endregion

  22.             #region Methods field
  23.             [Description("I'm CNBAStar's mothed ShowTime()",ExtraInfo="public")]
  24.             public string ShowTime()
  25.             { return mName + " is most famous basketball player of the world!"; }

  26.             [method: Description("I'm CNBAStar's mothed ShowTime2()")]
  27.             public string ShowTime2()
  28.             { return "Kobe Brynt is so so."; }

  29.             [return: Description("Just mark the return value of showTime3() ")]
  30.             public string ShowTime3()
  31.             { return "Lebron James is so so."; }
  32.             #endregion
  33.         }

  34.         static void Main(string[] args)
  35.         {
  36.             /* 反射出CNBAStar class中携带信息的方法 */
  37.             Object[] attrs = typeof(CNBAStar).GetCustomAttributes(true);
  38.             foreach (Object obj in attrs)
  39.             {
  40.                 if (obj is DescriptionAttribute)
  41.                 {
  42.                     Console.WriteLine((obj as DescriptionAttribute).MData);
  43.                     Console.WriteLine("===================================================");
  44.                 }
  45.             }

  46.             /* 反射出CNBAStar class中相关属性、方法所携带信息的方法:
  47.              * 先获取class.members,再取type.GetCustomAttributes() */
  48.             MemberInfo[] members = typeof(CNBAStar).GetMembers();
  49.             foreach (MemberInfo member in members)
  50.             { ParseAttributes(member); }

  51.             Console.ReadKey();
  52.         }


  53.         /** *************************************************************************************************
  54.          * DESC : 将class的members所携带的信息一 一进行反射
  55.          * ARGC :
  56.          * @type: member's all infomation.
  57.          * RET:
  58.          *---------------------------------------------------------------------------------------------------
  59.         ****************************************************************************************************/
  60.         static void ParseAttributes(MemberInfo type)
  61.         {
  62.             object[] attributes = type.GetCustomAttributes(true);
  63.             Console.WriteLine("{0} {1}'s attributes:", type.MemberType.ToString(), type.Name);

  64.             if (attributes.Length != 0)
  65.             {
  66.                 foreach (object attribute in attributes)
  67.                 {
  68.                     Console.WriteLine(" Attribute =[{0}]", attribute.ToString());
  69.                     DescriptionAttribute da = attribute as DescriptionAttribute;
  70.                     if (da != null)
  71.                     {
  72.                         Console.WriteLine(".Description = {0}",da.MData);
  73.                         if (da.ExtraInfo != "")
  74.                             Console.WriteLine(".ExtraInfo = {0}", da.ExtraInfo);
  75.                         else
  76.                             Console.WriteLine(".ExtraInfo=\"\"");
  77.                     }
  78.                     Console.WriteLine();
  79.                 }
  80.             }
  81.             else
  82.                 Console.WriteLine(" {0} has no attributes\n", type.Name);
  83.         }


  84.         [AttributeUsage(AttributeTargets.All)]
  85.         public class DescriptionAttribute : Attribute
  86.         {
  87.             private string mData;
  88.             private string mExtraInfo;
  89.             private string mThirdInfo;

  90.             public DescriptionAttribute(string data)
  91.             {
  92.                 mData = data;
  93.                 mExtraInfo = "";
  94.                 mThirdInfo = "";
  95.             }

  96.             public string MData
  97.             {
  98.                 get { return mData; }
  99.             }

  100.             /* Extra infomation */
  101.             public string ExtraInfo
  102.             {
  103.                 get { return mExtraInfo; }
  104.                 set { mExtraInfo = value; ; }
  105.             }

  106.             public string ThirdInfo
  107.             {
  108.                 get { return mThirdInfo; }
  109.                 set { mThirdInfo = value; ; }
  110.             }
  111.         }

  112.     }
  113. }


image

图2-1

    上图是使用程序中使用了[Description]属性的类、方法、Property被反射出的属性信息。

三、定位参数与命令参数

    自定义属性类中构造函数的参数称之为定位参数(即本例的data),任何公共读写字段或属性都是命令参数。两类参数的区别:

1、定位参数是构造函数带的参数,必须填写,下面是典型的报错:

  1. [Description]
  2. private string mName = "Michael Jordan";

错误    1    “CustomAttibute2.Program.DescriptionAttribute”不包含采用“0”参数的构造函数    

2、命令参数能选择性填写,并且顺序不要求。
    本例中的下面两种写法都是正确的

顺序一:

  1. [Description("I'm CNBAStar's mothed ShowTime()",ExtraInfo="public",ThirdInfo=="3#")]
  2. public string ShowTime()

顺序二:

  1. [Description("I'm CNBAStar's mothed ShowTime()",ThirdInfo=="3#",ExtraInfo="public")]
  2. public string ShowTime()

四、消除属性目标的歧义性

  1. [Description("I'm CNBAStar's mothed ShowTime()",ExtraInfo="public")]
  2. public string ShowTime()
  3. { return mName + " is most famous basketball player of the world!"; }

    上面代码中,虽然.NET内部将这个Description习惯归于ShowTime()方法,但表面上看这样的写法仍然让人容易误解:这个属性到底是属性方法ShowTime()还是属性它的返回值?

    为了解决这种歧义,在属性中添加了method和return参数作为区分,如下:

    属性标识方法ShowTime2()

  1. [method: Description("I'm CNBAStar's mothed ShowTime2()")]
  2. public string ShowTime2()
  3. { return "Kobe Brynt is so so."; }

    属性标识返回值

  1. [return: Description("Just mark the return value of showTime3() ")]
  2. public string ShowTime3()
  3. { return "Lebron James is so so."; }



参考文献:

1、http://edn.embarcadero.com/article/30250

Using Custom Attributes in C# - By David Clegg

2、http://msdn.microsoft.com/zh-cn/library/b3787ac0(v=vs.90).aspx 

消除属性目标的歧义性

3、http://database.ctocio.com.cn/4/9344004.shtml

SQLServer:如何使用C#自定义属性

4、http://www.csharpwin.com/csharpspace/11732r3341.shtml

如何在C#中自定义属性

相关文章
|
3月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
6月前
|
关系型数据库 MySQL C#
C# winform 一个窗体需要调用自定义用户控件的控件名称
给用户控件ucQRCode增加属性: //二维码图片 private PictureBox _pictureBoxFSHLQrCode; public PictureBox PictureBoxFSHLQrCode {   get { return _pictureBoxFSHLQrCode; }   set { this.pictureBoxFSHLQrCode = value; } } 在Form1窗体直接调用即可: ucQRCode uQRCode=new ucQRCode(); ucQRCode.PictureBoxFSHLQrCode.属性= 要复制或传给用户控件上的控件的值
37 0
|
1月前
|
C#
C#学习相关系列之自定义遍历器
C#学习相关系列之自定义遍历器
|
1月前
|
Java C#
C#学习相关系列之多线程(七)---Task的相关属性用法
C#学习相关系列之多线程(七)---Task的相关属性用法
|
3月前
|
开发框架 .NET C#
C# 10.0中的扩展属性与模式匹配:深入解析
【1月更文挑战第20天】C# 10.0引入了众多新特性,其中扩展属性与模式匹配的结合为开发者提供了更强大、更灵活的类型检查和代码分支能力。通过这一特性,开发者可以在不修改原始类的情况下,为其添加新的行为,并在模式匹配中利用这些扩展属性进行更精细的控制。本文将详细探讨C# 10.0中扩展属性与模式匹配的工作原理、使用场景以及最佳实践,帮助读者更好地理解和应用这一新功能。
|
3月前
|
运维 编译器 C#
C# 9.0中的本地函数属性:深化函数级别的控制
【1月更文挑战第17天】C# 9.0引入了本地函数属性的概念,允许开发者在本地函数上应用属性,从而进一步细化对函数行为的控制。这一新特性不仅增强了代码的可读性和可维护性,还为函数级别的编程提供了更多的灵活性。本文将探讨C# 9.0中本地函数属性的用法、优势以及可能的应用场景,帮助读者更好地理解并应用这一新功能。
|
3月前
|
设计模式 C#
C#反射机制实现开闭原则的简单工厂模式
C#反射机制实现开闭原则的简单工厂模式
18 0
|
4月前
|
XML 存储 JSON
C# | 使用Json序列化对象时忽略只读的属性
将对象序列化成为Json字符串是一个使用频率非常高的功能。Json格式具有很高的可读性,同时相较于XML更节省空间。 在开发过程中经常会遇到需要保存配置的场景,比如将配置信息保存在配置类型的实例中,再将这个对象序列化成为Json字符串并保存。当需要加载配置时,则是读取Json格式的字符串再将其还原成配置对象。在序列化的过程中,默认会将所有公开的属性和字段都序列化进入Json字符串中,这其中也会包含只读的属性或字段,而只读的属性和字段在反序列化的过程中其实是无意义的,也就是说这一部分存储是多余的。 本文将讲解如何在执行Json序列化时,忽略掉那些只读的属性和字段。
54 0
C# | 使用Json序列化对象时忽略只读的属性
|
4月前
|
存储 C# 开发者
C# | 通过反射将对象属性展示在TreeView中
在编程过程中,我们经常需要处理复杂的对象和数据结构。将这些数据结构展示在UI界面上是很有用的,可以帮助开发者更好地理解和分析数据。 而TreeView作为一种常见的控件,可以以树状结构的方式展示数据,非常适合用于展示层次化的对象。 本文将介绍如何使用TreeView控件展示一个对象,并且可以动态处理对象中的属性和子对象。通过本文的学习,您将学会如何更好地理解和展示数据,提高编程效率。
34 0
C# | 通过反射将对象属性展示在TreeView中
|
4月前
|
安全 C# 图形学
C#的反射机制
C#的反射机制