你必须知道的.NET之特性和属性

1、引言

attribute是.NET框架引入的一大技术亮点,因此我们有必要花点时间走进一个发现attribute登堂入室的入口。因为.NET Framework中使用了大量的定制特性来完成代码约定,[Serializable]、[Flags]、[DLLImport]、[AttributeUsage]这些构造,相信大家都见过吧(MVC中也有很多地方用到了特性),那么你是否了解其背后的技术。
提起特性,不免让人想起“属性”。特性和属性往往给初学者混淆的概念冲击,本文将对二者的概念、区别、用法、示例做以概括性的总结和比较。另外本文的主题以特性介绍为主,属性的论述重点突出在二者的比较上。

2、概念引入

2.1 什么是特性?
MADN的定义:公共语言运行时允许添加类似关键字的描述声明,叫做attribute,它对程序中的元素进行标注,如类型、字段、方法和属性等。Attribute和Microsoft .Net Framework文件的元数据(metadata)保存在一起,可以用来向运行时描述你的代码,或者在程序运行时影响程序的行为。
我们简单的总结为:定制特性attribute本质上是一个类,其为目标元素提供关联附加信息,并在运行期以反射的方式来获取附加信息。具体的特性实现方法,在接下来的讨论中继续深入。
2.2 什么是属性?
属性是面向对象编程的基本概念,提供了对私有化字段的访问封装,在c#中以get和set访问器方法实现对可读可写属性的操作,提供了安全和灵活的数据访问封装。以下是属性的简单示例:

class User
{
    private string name;
    public string Name
    {
        get { return (name == null) ? string.Empty : name; }
        set { name = value; }
    }
    private int age;
    public int Age
    {
        get { return age; }
        set
        {
            if (value > 0 && value < 160)
            {
                age = value;
            }
            else
            {
                throw new Exception("Not a valid age");
            }
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        User user = new User();
        user.Name = "蝈蝈";
        Console.WriteLine(user.Name);
        user.Age = 18;
        Console.WriteLine(user.Age);
        Console.ReadLine();
    }
}

2.3 区别和比较
通过对概念的澄清和历史的回溯,我们发现特性和属性只是在名称上有点瓜葛,在功能和应用上,二者其实没有太多模糊的概念交叉,因此没必要来比较其应用的异同点。本文则以特性的概念为重点,来讨论其应用的场合和规则。

3、通用规则

定制特性可以应用的目标元素为:程序集(assembly)、模块(module)、类型(type)、属性(property)、事件(event)、字段(field)、方法(method)、参数(param)、返回值(return),应该全了。

  • 定制特性以[,]形式展现,放在目标元素之上,多个特性可以应用于同一元素,特性之间以逗号隔开,以下表达规则有效:[AttributeUsage][Flags]、[AttributeUsage,Flags]、[AttributeUsageAttribute,Flags]、[Flags,AttributeUsageAttribute]、[AttributeUsage(),Flags()]。

  • 自定义特性类型必须直接或间接继承自System.Attribute类,而且该类型必须有公有构造函数来创建其实例。

  • 所有自定义的特性名称都应该有Atrribute后缀,这是约定。

  • attribute实例在编译期进行初始化,而不是运行期。
  • C#允许以指定的前缀来表示特性所应用的目标元素,建议这样来处理,因为显示处理可以消除可能带来的二义性。例如:
using System;
namespace TestAttribute
{
    [assembly:MyAttribute(1)]//应用于程序集
    [module:MyAttribute(2)]//应用于模块
    public class User()
    {...... 
    }
}
  • 定制特性可以用在其他定制特性上,因为定制特性本来就是一个类,遵守类的公有规则。例如很多时候我们的自定义定制特性会应用AttributeUsage特性,来控制如何应用新定义的特性。
[AttributeUsage(AttributeTarget.All),AllowMultiple=true,Inherited=true]
class MyAttribute:System.Attribute
{......
}
  • 定制特性不会影响应用元素的任何功能,只是约定了该元素具有的特质。
  • 所有非抽象特性必须具有public访问限制。
  • 特性常用于编译器指令,突破#define、#undefine、#if、#endif的限制,而且更加灵活。
  • 定制特性常用于在运行期获得代码注释信息,以附加信息来优化调试。
  • 定制特性可以应用在某些设计模式中,如工厂模式。
  • 定制特性还常应用于位标记、非托管函数标记、方法废弃标记等方面。

4、特性的应用

4.1 常用特性
事实上.NET框架已经提供了丰富的固有特性由我们发挥,以下精选出我认为最常用、最典型的固有特性做以简单讨论,从.NET提供的经典开始,或许是一种求知的捷径,希望能给大家以启示。

  • AttributeUsage
  • Flags
  • DllImport
  • Serializable
  • Conditional
  • Description
  • DefaultValue
  • Category
  • ReadOnly

4.2 自定义特性

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class VersionAttribute : System.Attribute
{
    public string Name { get; set; }
    public string Date { get; set; }
    public string Description { get; set; }
    public void Show()
    {
        Console.WriteLine("名称:{0} 日期:{1} 描述:{2}", Name, Date, Description);
    }
}
[Version(Name="版本检测",Date="2016-9-18",Description="刚会用来一发")]
public class MyClass
{

}
static void Main(string[] args)
{
    Type tp = typeof(MyClass);
    VersionAttribute version = (VersionAttribute)Attribute.GetCustomAttribute(tp, typeof(VersionAttribute));
    Console.WriteLine("Name=" + version.Name);
    Console.WriteLine("Date=" + version.Date);
    Console.WriteLine("Description=" + version.Description);
    version.Show();
    Console.ReadKey();
}

这里写图片描述
Attribute类是在编译的时候被实例化的,而不是像普通类那样在运行的时候才实例化,所以在Main()方法中可以在没有实例化MyClass对象的情况下获取到MyClass的VersionAttribute信息。由于Attribute类是在编译的时候被实例化的,所以你还可以用外部工具维护这些Attribute信息。

5、经典示例

5.1 小菜一碟

using System;
using System.Reflection;
static void Main(string[] args)
{
    Type tp = typeof(MyClass);
    VersionAttribute version = (VersionAttribute)Attribute.GetCustomAttribute(tp, typeof(VersionAttribute));
    Console.WriteLine("Name=" + version.Name);
    Console.WriteLine("Date=" + version.Date);
    Console.WriteLine("Description=" + version.Description);
    version.Show();
    tp = version.GetType();
    /*利用反射逐个获取属性值*/
    PropertyInfo namePI = tp.GetProperty("Name");
    PropertyInfo datePI = tp.GetProperty("Date");
    PropertyInfo descriptionPI = tp.GetProperty("Description");
    MethodInfo showMI = tp.GetMethod("Show");
    string name = namePI.GetValue(version, null).ToString();
    string date = datePI.GetValue(version, null).ToString();
    string description = descriptionPI.GetValue(version, null).ToString();
    Console.WriteLine("-------------------------");
    Console.WriteLine("Name=" + name);
    Console.WriteLine("Date=" + date);
    Console.WriteLine("Description=" + description);
    showMI.Invoke(version, null);
    Console.ReadKey();
}

这里写图片描述
5.2 他山之石
MSDN认为,特性(Attribute)描述如何将数据序列化,指定用于强制安全性的特性,并限制实时(JIT)编译器的优化,从而使代码易于调试。特性(Attribute)还可以记录文件名或代码作者,或在窗体开发阶段控制控件或成员的可见性。
dudu收藏的系列文章《Attribute在.net编程中的应用》,给你应用方面的启示会很多值得研究。http://www.cnblogs.com/dudu/articles/4451.html
亚历山大同志的系列文章《手把手教你写ORM(六)》中也有很好的诠释。http://www.cnblogs.com/Alexander-Lee/archive/2007/01/24/hbh-orm-06.html
idior的文章《Remoting基本原理及其扩展机制》也很有用,因此补充。http://www.cnblogs.com/idior/archive/2007/03/06/665479.html

6、结论

Attribute是.net引入的一大技术特色,现在应用已经非常广泛,MVC、jquery插件等都有特性应用的出现。更深层次的应用,例如序列化、程序安全性、设计模式等多方面都可以挖掘出闪耀的金子,有需要的同学可以继续研究。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
.NET 中,获取属性特性可以通过使用属性修饰符来实现。属性修饰符可以为属性添加元数据(Metadata),这些元数据可以描述属性的特征,例如可写性、可读性、默认值等等。 以下是一些常用的属性修饰符: 1. `[Browsable(true/false)]` - 指定属性是否可浏览。 2. `[ReadOnly(true/false)]` - 指定属性是否只读。 3. `[DefaultValue(value)]` - 指定属性的默认值。 4. `[Description("description")]` - 指定属性的描述信息。 5. `[Category("category")]` - 指定属性所属的类别。 6. `[Editor(typeof(editor), typeof(UITypeEditor))]` - 指定属性的编辑器类型。 例如,以下是一个示例类,其中包含一个使用了属性修饰符的属性: ``` public class MyClass { [Browsable(true)] [ReadOnly(false)] [DefaultValue(10)] [Description("This is my property")] [Category("My category")] [Editor(typeof(MyEditor), typeof(UITypeEditor))] public int MyProperty { get; set; } } ``` 在这个示例中,我们定义了一个名为 MyProperty 的属性,并使用了多个属性修饰符来描述它的特征。例如,我们指定了它可浏览、可写,具有默认值 10,具有描述信息和类别,并且使用了自定义的编辑器类型。 在使用该类时,我们可以通过反射来访问这些属性的修饰符,例如: ``` var propertyInfo = typeof(MyClass).GetProperty("MyProperty"); var attributes = propertyInfo.GetCustomAttributes(true); foreach (var attribute in attributes) { Console.WriteLine(attribute.ToString()); } ``` 这里,我们使用反射获取 MyProperty 属性的 PropertyInfo 对象,并使用 GetCustomAttributes 方法获取它的所有属性修饰符。然后,我们遍历这些修饰符并输出它们的字符串表示形式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值