您的位置:首页 > 编程语言 > C#

【C#语法】类和方法的特性Attribute

2017-07-03 20:28 381 查看

一、引言        

        今天,我们来聊一下C#中的特性Attribute。何为特性Attribute?我们先看一个特性的使用例子,我们定义了一个Human类,但是由于某种原因该类不再被使用,但是我又不想将该类的代码注释或者删除掉,于是我们就可以通过给它赋予Obsolete特性来禁止别人使用:

[Obsolete("该类已经过时,不能再使用",true)]
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
        当我们在代码中使用该类时,发现编译器会报错,并提示我们自定义的提示信息。

        这是在main函数中使用Human类:

class Program
{
static void Main(string[] args)
{
Human human;
}
}
        这是编译器报的错误:



        我们在Human类前面添加的obsolete就是该类的一个特性,与之相对,我们接触最多的应该是类的属性Property,Human类的Name和Child就是其两个属性。特性本质就是一个类,Obsolete中传递的两个参数就是该类的构造函数所需的参数,第一个是在编译出错时编译器要提示的字符串,第二个是指是否
报错,如果为true编译时就会报错。特性除了可以放到类前面之外,也可以放到方法和属性的前面。

二、特性属于类而非属于对象

        在很多的资料中,都把特性比作类在某一特性环境下的属性。比如对于Human类,把一个人放到学校中它就有年级等特性,把它放到公司中就有部门等特性,这种特性不是它与生既来的(与生既来的是属性Proerty),而是随着环境的不同而发生变化。虽然这种解释很形象,但是很容易让人发生误解——某一个对象具有特性!而实际上,特性是属于类而非一个对象,这点类似于类的静态成员,我们不能通过一个human实例获取Human类的特性,只能通过诸如以下的语句来获取其特性:

object[] attributes = typeof(Human).GetCustomAttributes(true);
        其实,要想理解这个问题。我们需要了解特性的用途:特性不是给程序员用的,而是给编译器看的。它告诉编译器这个类具有何特性,在何种情况下应该作何处理!比如在上面的类型中,告诉编译器该类已经不能被使用了;再比如我们在类前面添加
[Serializable]特性,告诉编译器,该类支持序列化。

三、自定义特性

在前面的例子中,我们提到过,特性的本质其实就是一个类,这个类必须继承自Attribute基类,而且类名一般要求格式为“名称+Attribute”的形式。我们现在为Human类定义一个Help的属性,来告诉使用者Human类的信息:
public class HelpAttribute : Attribute
{
public Help(string info)
{
this.Info = info;
}
public string Info { get; private set; }
}
我们在使用时可以加Attribute或者不加Attribute,如下面的格式:
[Help("这是一个Human类")]
或者
 [HelpAttribute("这是一个Human类")]
因为编译器在处理特性时会先查找特性名称,如果找不到就自动加上Attribute再次进行查找。
我们在主函数中查找类的特性并输出:
static void Main(string[] args)
{
object[] attributes = typeof(Human).GetCustomAttributes(true);
HelpAttribute attribute=attributes[0] as HelpAttribute;
Console.WriteLine(attribute.Info);
}
得到的结果如下:



四、使用转换类TypeConvertAttribute

        接下来,定义一个用于进行类型转换的类,我们将字符串转换成human类对象:

public class StringToHumanConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is String)
{
Human h = new Human();
h.Name = value as String;
return h;
}
return base.ConvertFrom(context, culture, value);
}
}
        接下来,将特性赋予Human类 :

[TypeConverterAttribute(typeof(StringToHumanConverter))]
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}

        我们定义的这个类,不能在cs代码中直接用来将字符串和Human类对象的隐式转换,诸如下面的用法是错误的:

Human human = str as Human;
       我们想在cs代码中进行转换,只能定义一个StringToHumanConverter对象,调用其ConverFrom方法进行转换:

String str = "hyman";
StringToHumanConverter convert = new StringToHumanConverter();
Human human = (Human)convert.ConvertFrom(str);

        但是这种转换可以在XMAL中直接使用:

<Window.Resources>
<local:Human x:Key="human" Child="tom"/>
</Window.Resources>        我们在后台代码中可以通过FindResource找到该资源,发现已经可以正常打印出其Child的Name,这是因为WPF的框架自动调用TypeConverter进行了转换:
private void button1_Click(object sender, RoutedEventArgs e)
{
Human human = (Human)this.FindResource("human");
MessageBox.Show(human.Child.Name);
}


        
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: