c#之Attribute特性的原理

简介: c#之Attribute特性的原理

当我们在Visual Studio添加一个自定义控件时,它都会给我们以下默认的代码。

[DefaultProperty("Text")]   
    [ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]   
    public class WebCustomControl1 : WebControl   
    {   
        [Bindable(true)]   
        [Category("Appearance")]   
        [DefaultValue("")]   
        [Localizable(true)]   
        public string Text   
        {   
            get  
            {   
                String s = (String)ViewState["Text"];   
                return ((s == null) ? String.Empty : s);   
            }   
            set  
            {   
                ViewState["Text"] = value;   
            }   
        }   
        protected override void RenderContents(HtmlTextWriter output)   
        {   
            output.Write(Text);   
        }   
    }  
[DefaultProperty("Text")]
    [ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
    public class WebCustomControl1 : WebControl
    {
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Text
        {
            get
            {
                String s = (String)ViewState["Text"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                ViewState["Text"] = value;
            }
        }
        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write(Text);
        }
    } 

在这个控件中有个默认的属性"Text",在这个属性有[DefaultValue("")]相应的特性,来给该属性设置默认值。以前一直

想不明白微软是怎么实现的,直到昨天看了《你必须知道的.Net》中讲“特性”这一章受到了启发。于是我马上去试试,

还真的可以。废话少说,来看看我的实现方法。

首先我们先创建一个自己默认值特性SelfDefaultValueAttribute:

[AttributeUsageAttribute(AttributeTargets.All,   //     可以对任何应用程序元素应用属性       
       AllowMultiple = true,                        //     允许指定多个实例      
       Inherited = false)]                          //     不继承到派生类   
   public  class SelfDefaultValueAttribute : System.Attribute   
   {   
       public SelfDefaultValueAttribute(object defaultVale)   
       {   
           this.AttrValue = defaultVale;   
       }   
       public object AttrValue   
       {   
           get;   
           set;   
       }   
   }  
 [AttributeUsageAttribute(AttributeTargets.All,   //     可以对任何应用程序元素应用属性    
        AllowMultiple = true,                        //     允许指定多个实例   
        Inherited = false)]                          //     不继承到派生类
    public  class SelfDefaultValueAttribute : System.Attribute
    {
        public SelfDefaultValueAttribute(object defaultVale)
        {
            this.AttrValue = defaultVale;
        }
        public object AttrValue
        {
            get;
            set;
        }
    } 

接着我们创建一个自己的控件父类SelfControl

public  class SelfControl      
 { 
   public SelfControl()           
  {             
    Type tp = this.GetType();              
    PropertyInfo[] propInfoList = tp.GetProperties();   //获得所有的属性        
      foreach (PropertyInfo p in propInfoList)              
      {  
      //获得当前属性的特性                  
      SelfDefaultValueAttribute m = Attribute.GetCustomAttribute(p, typeof (SelfDefaultValueAttribute)) as SelfDefaultValueAttribute;                     
    //判断该属性是否有特性                   
    if (m != null)                   
    {                       
      //设置默认值                       
      p.SetValue(this, m.AttrValue, null);                   
    }                   
    else                  
    {                       
      //设置值为空                       
      p.SetValue(this, null, null);                   
    }               
    }           
  }
  [SelfDefaultValue("")]          
  public virtual string Name          
  {              
    get;              
    set;          
  }       
}   
public class SelfControl    
{  
    public SelfControl()        
   {            
      Type tp = this.GetType();            
      PropertyInfo[] propInfoList = tp.GetProperties();   
      //获得所有的属性
        foreach (PropertyInfo p in propInfoList)
            {
                SelfDefaultValueAttribute m = Attribute.GetCustomAttribute(p, typeof
(SelfDefaultValueAttribute)) as SelfDefaultValueAttribute;                //获得当前属性的特性
           /*判断该属性是否有特性*/
                if (m != null)
                {
                    /*设置默认值*/
                    p.SetValue(this, m.AttrValue, null);
                }
                else
                {
                    /*设置值为空*/
                    p.SetValue(this, null, null);
                }
            }
        }
       [SelfDefaultValue("")]
       public virtual string Name
       {
           get;
           set;
       }
    } 

这个控件只有一个属性"Name"默认值为空。说明一下的是,在这里我们用到了反射的机制,所以我们要引入空间:

System.Reflection。

现在,我们就可以创建属于自己定义的控件了。

好了,终于完成了。那我们现在来测试一下。

public class Myrun   
   {   
       public static void Main(string[] args)   
       {   
           TestSelfControl selfCon = new TestSelfControl();   
           Console.WriteLine("控件宽度:{0}",selfCon.Width);   
           Console.WriteLine("控件高度:{0}", selfCon.Height);   
           Console.WriteLine("控件名字:{0}", selfCon.Name);   
           Console.WriteLine("控件标签:{0}", selfCon.HtmlTag);   
           Console.WriteLine("控件文本:{0}", selfCon.Text);   
           Console.ReadLine();   
       }   
   }  
public class Myrun
   {
       public static void Main(string[] args)
       {
           TestSelfControl selfCon = new TestSelfControl();
           Console.WriteLine("控件宽度:{0}",selfCon.Width);
           Console.WriteLine("控件高度:{0}", selfCon.Height);
           Console.WriteLine("控件名字:{0}", selfCon.Name);
           Console.WriteLine("控件标签:{0}", selfCon.HtmlTag);
           Console.WriteLine("控件文本:{0}", selfCon.Text);
           Console.ReadLine();
       }
   } 
最后的结果就是:
view plaincopy to clipboardprint?
控件宽度:100   
控件高度:0   
控件名字:   
控件标签:   
控件文本:TestControl  
控件宽度:100
控件高度:0
控件名字:
控件标签:
控件文本:TestControl 

由于我们没给控件的高度设置默认值、高度类型Int,所以高度默认为0;而名字和标签类型为String,所以为空。

相关文章
|
1月前
|
C#
C#学习相关系列之数据类型类的三大特性(二)
C#学习相关系列之数据类型类的三大特性(二)
|
3月前
|
编译器 C# 开发者
C# 11.0中的新特性:覆盖默认接口方法
C# 11.0进一步增强了接口的灵活性,引入了覆盖默认接口方法的能力。这一新特性允许类在实现接口时,不仅可以提供接口中未实现的方法的具体实现,还可以覆盖接口中定义的默认方法实现。本文将详细介绍C# 11.0中接口默认方法覆盖的工作原理、使用场景及其对现有代码的影响,帮助开发者更好地理解和应用这一新功能。
|
3月前
|
编译器 C# 开发者
C# 9.0中的顶级语句:简化程序入口的新特性
【1月更文挑战第13天】本文介绍了C# 9.0中引入的顶级语句(Top-level statements)特性,该特性允许开发者在不使用传统的类和方法结构的情况下编写简洁的程序入口代码。文章详细阐述了顶级语句的语法、使用场景以及与传统程序结构的区别,并通过示例代码展示了其在实际应用中的便捷性。
|
API C#
C#反射与特性(三):反射类型的成员
C#反射与特性(三):反射类型的成员
251 0
|
3月前
|
开发框架 .NET Java
ASP.NET Core高级编程--C#基本特性(一)
本文章简略介绍C#的部分特性
|
9月前
|
数据可视化 程序员 C#
C# 面向对象三大特性
C# 面向对象三大特性
68 0
|
缓存 IDE API
C#反射与特性(五):主类型成员操作
C#反射与特性(五):主类型成员操作
337 0
C#反射与特性(五):主类型成员操作
|
C# 图形学
C#——特性
C#——特性
55 0
|
开发框架 .NET C#
C#版本与. NET版本对应关系以及各版本的特性
C#版本与. NET版本对应关系以及各版本的特性
447 0
|
C# 索引
【全栈计划 —— 编程语言之C#】总结深入面向对象三大特性之二 —— 继承性
【全栈计划 —— 编程语言之C#】总结深入面向对象三大特性之二 —— 继承性
80 0
【全栈计划 —— 编程语言之C#】总结深入面向对象三大特性之二 —— 继承性