C#特性

<1>

 

C#特性学习笔记

特性标签的本质:
1>特性是一个类,这个类的声明我们有一个规范,即:以Attribute结尾,例如MyClassAttribute 。当着仅仅是一个规范,如果你是在不以Attribute结尾也没关系。
2>这个类一定要继承自Attribute类。只有继承Attribute类,这个类才是一个特性
注意点:比如一个特性类的名称是MyClassAttribute ,当我们在某个类,方法,属性,字段贴这个特性标签的时候,可以省略它后面的Attribute 直接这样贴就可以 ,如:[MyClass]  当然 你也可以写全称,如[MyClassAttribute]

既然[MyClass] 等于 new MyClassAttribute()  那么很多逻辑就在特性的构造函数中去实现。然后再有需要的类或者其成员上打上特性标签

系统自带特性的介绍

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication1
{
    //Attribute 类
    //TypeId属性: 当在派生类中实现时,获取该 Attribute 的唯一标识符。


    //AttributeUsageAttribute 类   (AttributeUsageAttribute 类是继承自 Attribute 的)
    //AttributeUsageAttribute.Inherited 属性:获取或设置一个布尔值,该值指示指示的属性能否由派生类和重写成员继承。如果该属性可由派生类和重写成员继承,则为 true,否则为 false。默认为 true。
    //AttributeUsageAttribute.AllowMultiple 属性:获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示属性实例。如果允许指定多个实例,则为 true;否则为 false。默认为 false。
    //AttributeUsageAttribute.ValidOn 属性:获取一组值,这组值标识指示的属性可应用到的程序元素。属性值:一个或多个 AttributeTargets 值。默认为 All。


    //注意:对于一个特性类使用Attribute后缀是一个惯例。然而,如果不添加编译器会自动添加匹配。


    //限定特性类的应用范围  (这里规定ClassMsg这个特性类只能用于类和字段)
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
    //定制MsgAttribute特性类,继承于Attribute  
    public class ClassMsgAttribute : Attribute
    {
        //定义_msg字段和Msg属性//Msg属性用于读写msg字段  
        string _msg;
        public string Msg { get { return _msg; } set { _msg = value; } }
        public ClassMsgAttribute() { }
        //重载构造函数接收一个参数,赋值给_msg字段  
        public ClassMsgAttribute(string s) { _msg = s; }
    }



    //---------------------调用ClassMsg这个特性---------------------//

    //在Person类上标记ClassMsg特性  
    [ClassMsg(Msg = "这是关于人的姓名信息的类")]
    class Person
    {
        //在_name字段上应用ClassMsg特性  
        [ClassMsg("这是存储姓名的字段")]
        string _name;
        //以下特性无法应用,因为MsgAttribute定义的特性只能用于类和字段  
        //[ClassMsg("这是读写姓名字段的属性")]  
        public string Name { get { return _name; } set { _name = value; } }
    }  

}

另外我们在来看看系统自带的一个 [Obsolete] 特性,这个特性的作用就是标记某个方法是否已经过时的
例如:
定义一个Pigcs类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace 特性学习
{
    public class Pigcs
    {
        [Obsolete("此方法已经过时,请调用新的方法NewEat()")] //这个Obsolete特性是专门用来告诉用户某些方法或成员已经过时的消息
        public string OldEat()
        {
            return "我是老的方法";
        }

         public string  NewEat()
        {
            return "我是新的方法";
        }
    }
}
我们定义了这个Pigcs类,并在它的OldEat()方法上使用了[Obsolete]这个系统特性。看看效果怎么样

我们在来看看微软自带的这个ObsoleteAttribute特性类


自定义特性,及自定义特性的继承

自定义特性的定义

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace 特性学习
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class VipAttribute : Attribute //自定义一个Vip特性
    {

    }


    public class Vip5Attribute : VipAttribute //此时Vip5Attribute类也是一个特性了。它默认继承了父类的[AttributeUsage(AttributeTargets.Class| AttributeTargets.Method,AllowMultiple=true,Inherited=true)]
    {

    }

    //现在问题来了: Vip5Attribute继承了VipAttribute,因为VipAttribute这个特性只能用于类和方法,那么这个Vip5Attribute也就只能用在类,和方法上面,那假如我们这个Vip5Attribute想用在类和方法和属性上怎么办呢?
    //答案很简单,只要在Vip5Attribute这个特性上加系统特性就好了,如下:
    //只要在Vip5Attribute类上打上 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method |AttributeTargets.Property] 就可以了。

    //特别要注意,如果在子类上不打特性标签,就默认继承父类的特性标签,但是如果在子类上打了特性标签,就等于覆盖了父类的特性标签。
    //例如在子类上打: [AttributeUsage(AttributeTargets.Class] 那么它就只能用于类,而不能像父类那样用于方法 
    //[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method |AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    //public class Vip5Attribute : VipAttribute
    //{

    //}
}

实现一个登陆验证的特性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;

namespace 检查登陆验证.Attributes
{
    [AttributeUsage(AttributeTargets.Class)]  //这个特性只能用于类
    public class CheckLoginAttribute : Attribute //定义一个名字叫CheckLoginAttribute 的特性,用户检查用户是否已经登录
    {

        //我们知道在一个类上打上[CheckLogin] 就等于 new CheckLoginAttribute() 所以我们在这里定义了这个CheckLoginAttribute特性的不带参数的构造函数,在构造函数中判断用户是否已经登录。如果用户未登录,那么就跳到Login.aspx页面
        public  CheckLoginAttribute()
        {
            if (HttpContext.Current.Session["UserName"] == null)
            {
                HttpContext.Current.Response.Redirect("Login.aspx");
            }
        }
       
    }
}

特性还有其他的用法


定义一个特性
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace 特性学习
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method|AttributeTargets.Field|AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public class VipAttribute : Attribute //自定义一个Vip特性
    {
        string name;
        public string Name { get { return name; } }

        public VipAttribute(string disName)
        {
            this.name = disName; //构造函数初始化私有字段name         
        }
    }
}

假如我有两个类。一个是Pig类(猪) 一个是Dog类 (狗)
Pig类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace 特性学习
{
    public class Pig
    {
        [Vip("猪名字")]
        public string Name { get; set; }

        [Vip("猪年龄")]
        public int Age { get; set; }

    }
}
Dog类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace 特性学习
{
    public class Dog
    {
        [Vip("狗名字")]
        public string Name { get; set; }
        [Vip("狗年龄")]
        public int Age { get; set; }
    }
}
根据需求,其实实际就是根据类型来获取类型属性上的的特性标签里的参数值 


用法:
首先创建一个WebFrom页面
WebForm1.aspx文件
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="特性学习.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    </div>
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <br />
        <asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>
        <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
    </form>
</body>
</html>
WebFrom1.aspx.cs文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace 特性学习
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

            /*
             Pig p = new Pig();
            Type t = p.GetType();

            //获取Pig类中的Name属性
            PropertyInfo propName = t.GetProperty("Name");
            PropertyInfo propAge = t.GetProperty("Age");

            //检查Name这个属性上有没有[Vip]这个特性标签
            bool bName = propName.IsDefined(typeof(VipAttribute));

            bool bAge = propAge.IsDefined(typeof(VipAttribute));


            if (bName)
            {
                //如果Name属性上有[Vip]这个特性标签,那么就获取这个特性标签
                Attribute attr = propName.GetCustomAttribute(typeof(VipAttribute));

                VipAttribute vip = attr as VipAttribute; //转换一下类型

                this.Label1.Text = vip.Name;
               
            }

            if (bAge)
            {
                //如果Name属性上有[Vip]这个特性标签,那么就获取这个特性标签
                Attribute attr = propAge.GetCustomAttribute(typeof(VipAttribute));

                VipAttribute vip = attr as VipAttribute; //转换一下类型

                this.Label2.Text = vip.Name;

            }
            */
            //----------------------优化一下代码------------------------


            Pig pp = new Pig();  //根据类型来获取类型对应的属性特性标记值,如获取这个[VIP(猪名字)]特性标记里的”猪名字“
            // Dog pp = new Dog();

            Type tt = pp.GetType();

            //获取Pig类型的所有属性
            PropertyInfo[] pros = tt.GetProperties();

            //遍历属性
            foreach (var a in pros)
            {
                //VipAttribute vipattr = a.GetCustomAttribute<VipAttribute>(); //这样写。或者下面的写法

                //获取这个属性上的[vip]标签
                Attribute attr = a.GetCustomAttribute(typeof(VipAttribute));
                //类型转换
                VipAttribute vip = attr as VipAttribute;
                switch (a.Name)
                {
                    case "Name": this.Label1.Text = vip.Name; break;
                    case "Age": this.Label2.Text = vip.Name; break;

                }
            }

        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值