提起
c#中的属性和特性,对于初学者,常常认为二者存在某种必然的联系。它们一个叫property(属性),一个叫attribute(特性),译成中文后,由于名称很相似,而且MSDN中将二者都翻译为属性,致使很多人将二者视为同一类概念,其实它们之间并没有模糊的概念交叉,我们完全可以分开各自理解,没有必要也没法比较二者的异同点。因此,本文主要讨论属性和特性的概念以及如何使用。
1 属性
1.1又叫智能字段,它是面向对象编程语言的一个基本概念,提供了安全和灵活的数据访问封装,在C#中以get和set访问器方法实现对可读可写属性的操作,get访问器通过return来读取属性的值,set访问器通过value来设置属性的值。用法很简单,可参看代码示例。
1.2 属性和字段最本质的区别是属性不代表存储位置。
1.3 应用场合:当我们对字段赋值时需要进行合法性检查以避免非法数据的赋值,或需要进行只读只写的控制设置,或值的变化会导致某个对象的状态发生变化时,就需要通过属性来封装该字段,同时微软不提倡将字段的访问级别设为public以使用户可以在类外随意操作,而是通过采用属性来表示那些有必要在类外可见的字段。
Code
1. using System;
2. class MyClass
3. {
4. string name;
5. public string Name
6. {
7. get
8. {
9. if (name == null || name == String.Empty)
10. {
11. name = "name is empty";
12. }
13. return name;
14. }
15. set
16. {
17. if (value== null || value == String.Empty)
18. {
19. throw new Exception("the name is valid");
20. }
21. name = value;
22. }
23. }
24. }
25.
26. class Test
27. {
28. public static void Main()
29. {
30. MyClass myObject=new MyClass();
31.
32. // Call Name.Get()
33. Console.Write(myObject.Name);
34.
35. // Call Name.Set()
36. myObject.Name = "My Object"; // If myObject.Name = null, will throw exception
37.
38. // Call Name.Get()
39. Console.Write(myObject.Name);
40. Console.Read();
41. }
42. }
2 特性
2.1 说穿了,特性本质上是一个类,用来为目标元素提供附加信息,并在运行时通过反射机制来获取这些信息以影响或控制应用程序运行时的行为。目标元素可以是程序集、类、构造函数、委托、枚举、事件、字段、接口、方法、可移植可执行文件模块、参数、属性、返回值、结构或其他特性。
2.2 在.Net Framework预定义的特性中,我们经常用到的主要有Serializable、DllImport、AttributeUsage、Conditional、Flags等,本文只点出这些关键词,至于用法及含义可参看MSDN中相关类(SerializableAttribute、DllImportAttribute…)。
2.3 自定义特性的实现及其使用较为简单,参看下述经典示例代码,你就会明白一切了。只是要注意以下几点:
Ø 定制特性以[,]形式展现,放置在目标元素的上方;
Ø 必须直接或者间接继承System.Attribute类;
Ø 名称必须包含Attribute后缀,这是习惯性约定;
Ø 特性不会影响目标元素的任何功能,只是约定了该元素具有的特质。
Code
# using System;
# using System.Reflection; //应用反射技术获得特性信息
#
# namespace Anytao.net
# {
# //定制特性也可以应用在其他定制特性上,
# //应用AttributeUsage,来控制如何应用新定义的特性
# [AttributeUsageAttribute(AttributeTargets.All, //可应用任何元素
# AllowMultiple = true, //允许应用多次
# Inherited = false)] //不继承到派生类
# //特性也是一个类,
# //必须继承自System.Attribute类,
# //命名规范为:"类名"+Attribute。
# public class MyselfAttribute : System.Attribute
# {
# //定义字段
# private string _name;
# private int _age;
# private string _memo;
#
# //必须定义其构造函数,如果不定义有编译器提供无参默认构造函数
# public MyselfAttribute()
# {
# }
# public MyselfAttribute(string name, int age)
# {
# _name = name;
# _age = age;
# }
#
# //定义属性
# //显然特性和属性不是一回事儿
# public string Name
# {
# get { return _name == null ? string.Empty : _name; }
# }
#
# public int Age
# {
# get { return _age; }
# }
#
# public string Memo
# {
# get { return _memo; }
# set { _memo = value; }
# }
#
# //定义方法
# public void ShowName()
# {
# Console.WriteLine("Hello, {0}", _name == null ? "world." : _name);
# }
# }
#
# //应用自定义特性
# //可以以Myself或者MyselfAttribute作为特性名
# //可以给属性Memo赋值
# [Myself("Emma", 25, Memo = "Emma is my good girl.")]
# public class Mytest
# {
# public void SayHello()
# {
# Console.WriteLine("Hello, my.net world.");
# }
# }
#
# public class Myrun
# {
# public static void Main(string[] args)
# {
# //如何以反射确定特性信息
# Type tp = typeof(Mytest);
# MemberInfo info = tp;
# MyselfAttribute myAttribute =
# (MyselfAttribute)Attribute.GetCustomAttribute(info, typeof(MyselfAttribute));
# if (myAttribute != null)
# {
# //嘿嘿,在运行时查看注释内容,是不是很爽
# Console.WriteLine("Name: {0}", myAttribute.Name);
# Console.WriteLine("Age: {0}", myAttribute.Age);
# Console.WriteLine("Memo of {0} is {1}", myAttribute.Name, myAttribute.Memo);
# myAttribute.ShowName();
# }
#
# //多点反射
# object obj = Activator.CreateInstance(typeof(Mytest));
#
# MethodInfo mi = tp.GetMethod("SayHello");
# mi.Invoke(obj, null);
# Console.ReadLine();
# }
# }
# }