• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#中的Attribute

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

 以下部分内容及代码来源于《C#技术揭秘》(Inside C# Sencond Edition)

定义属性:
        属性实际上是一个派生自System.Attribute基类的类。System.Attribute类含有几个用于访问和检查自定义属性的方法。尽管你有权将任何类定义为属性,但是按照惯例来说,从System.Attribute派生类是有意义的。示例如下:
     public enum RegHives
     {
         HKEY_CLASSES_ROOT,
         HKEY_CURRENT_USER,
         HKEY_LOCAL_MACHINE,
         HKEY_USERS,
         HKEY_CURRENT_CONFIG
     }
 
     public class RegKeyAttribute : Attribute
     {
         public RegKeyAttribute(RegHives Hive, String ValueName)
         {
              this.Hive = Hive;
              this.ValueName = ValueName;
         }
 
         protected RegHives hive;
         public RegHives Hive
         {
              get { return hive; }
              set { hive = value; }
         }
 
         protected String valueName;
         public String ValueName
         {
              get { return valueName; }
              set { valueName = value; }
         }
     }
我们在这里添加了不同注册表的枚举、属性类的构造器以及两个特性(Property)。在定义属性时你可以做许许多多的事情,下面我们看看如何在运行时查询属性。要想在运行时查询类型或成员所附着的属性,必须使用反射.
查询类属性:
        假设你希望定义一个属性,这个属性定义了将在其上创建对象的远程服务器。如果没有这个属性,就要把此信息保存在一个常量中或是一个应用程序的资源文件中。通过使用属性,只需用以下方法标注出类的远程服务器名即可:
using System;
 
namespace QueryAttribs
{
     public enum RemoteServers
     {
         JEANVALJEAN,
         JAVERT,
         COSETTE 
     }
 
     public class RemoteObjectAttribute : Attribute
     {
         public RemoteObjectAttribute(RemoteServers Server)
         {
              this.server = Server;
         }
 
         protected RemoteServers server;
         public string Server
         {
              get
              {
                  return RemoteServers.GetName(
                       typeof(RemoteServers), this.server);
              }
         }
     }
 
     [RemoteObject(RemoteServers.COSETTE)]
     class MyRemotableClass
     {
     }
     class Test
     {
         [STAThread]
         static void Main(string[] args)
         {
              Type type = typeof(MyRemotableClass);
              foreach (Attribute attr in
                  type.GetCustomAttributes(true))
              {
                  RemoteObjectAttribute remoteAttr =
                       attr as RemoteObjectAttribute;
                  if (null != remoteAttr)
                  {
                  Console.WriteLine(
                           "Create this object on {0}.",
                           remoteAttr.Server);
                  }
              }
 
              Console.ReadLine();
         }
     }
}
运行结果为:
Creat this object on COSETTE。
注意:在这个例子中的属性类名具有Attribute后缀。但是,当我们将此属性附着给类型或成员时却不包括Attribute后缀。这是C#语言的设计者提供的简单方式。当编译器看到一个属性被附着给一个类型或成员时,它会搜索具有指定属性名的System.Attribute派生类。如果编译器没有找到匹配的类,它就在指定的属性名后面加上Attribute,然后再进行搜索。因此,常见的使用做法是将属性类名定义为以Attribute结尾,在使用时忽略名称的这一部分。以下的代码都采用这种命名方式。
查询方法属性:
        在下面这个例子中,我们使用属性将方法定义为可事务化的方法,只要存在TransactionableAttribute属性,代码就知道具有这个属性的方法可以属于一个事务。
using System;
using System.Reflection;
 
namespace MethodAttribs
{
     public class TransactionableAttribute : Attribute
     {
         public TransactionableAttribute()
         {
         }
     }
 
     class SomeClass
     {
         [Transactionable]
         public void Foo()
         {}
 
         public void Bar()
         {}
 
         [Transactionable]
         public void Goo()
         {}
     }
 
     class Test
     {
         [STAThread]
         static void Main(string[] args)
         {
              Type type = Type.GetType("MethodAttribs.SomeClass");
              foreach (MethodInfo method in type.GetMethods())
              {
                  foreach (Attribute attr in
                       method.GetCustomAttributes(true))
                  {
                       if (attr is TransactionableAttribute)
                       {
                           Console.WriteLine(
                                "{0} is transactionable.",
                                method.Name);
                       }
                  }
              }
 
              Console.ReadLine();
         }
     }
}
运行结果如下:
Foo is transactionable.
Goo is transactionable.
 
查询字段属性:
        假设有一个类含有一些字段,我们希望将它们的值保存进注册表。为此,可以使用以枚举值和字符串为参数的构造器定义一个属性,这个枚举值代表正确的注册表hive,字符串代表注册表值名称。在运行时可以查询字段的注册表键。
using System;
using System.Reflection;
 
namespace FieldAttribs
{
     public enum RegHives
     {
         HKEY_CLASSES_ROOT,
         HKEY_CURRENT_USER,
         HKEY_LOCAL_MACHINE,
         HKEY_USERS,
         HKEY_CURRENT_CONFIG
     }
 
     public class RegKeyAttribute : Attribute
     {
         public RegKeyAttribute(RegHives Hive, String ValueName)
         {
              this.Hive = Hive;
              this.ValueName = ValueName;
         }
 
         protected RegHives hive;
         public RegHives Hive
         {
              get { return hive; }
              set { hive = value; }
         }
 
         protected String valueName;
         public String ValueName
         {
              get { return valueName; }
              set { valueName = value; }
         }
     }
 
     class SomeClass
     {
         [RegKey(RegHives.HKEY_CURRENT_USER, "Foo")]
         public int Foo;
 
         public int Bar;
     }
 
     class Test
     {
         [STAThread]
         static void Main(string[] args)
         {
              Type type = Type.GetType("FieldAttribs.SomeClass");
              foreach (FieldInfo field in type.GetFields())
              {
                  foreach (Attribute attr in
                       field.GetCustomAttributes(true))
                  {
                       RegKeyAttribute rka =
                           attr as RegKeyAttribute;
                       if (null != rka)
                       {
                           Console.WriteLine(
                                "{0} will be saved in"
                                + " {1}////{2}",
                                field.Name,
                                rka.Hive,
                                rka.ValueName);
                       }
                  }
              }
 
              Console.ReadLine();
         }
     }
}
运行结果为:
Foo will be saved in HKEY_CURRENT_USER//Foo
 
        大家可以看到,用属性来标注类、方法、字段,既可以把用户的自定义信息附属在实体上,又可以在运行时动态的查询。下面我将讲一些C#中默认的预定义属性,见下表:
预定义的属性
有效目标
说明
AttributeUsage
Class
指定另一个属性类的有效使用方式
CLSCompliant
全部
指出程序元素是否与CLS兼容
Conditional
Method
指出如果没有定义相关联的字符串,编译器就可以忽略对这个方法的任何调用
DllImport
Method
指定包含外部方法的实现的DLL位置
STAThread
Method(Main)
指出程序的默认线程模型为STA
MTAThread
Method(Main)
指出程序的默认模型为多线程(MTA)
Obsolete
除了Assembly、Module、Parameter和Return
将一个元素标示为不可用,通知用户此元素将被从未来的产品
ParamArray
Parameter
允许单个参数被隐式地当作params(数组)参数对待
Serializable
Class、Struct、enum、delegate
指定这种类型的所有公共和私有字段可以被串行化
NonSerialized
Field
应用于被标示为可串行化的类的字段,指出这些字段将不可被串行化
StructLayout
Class、struct
指定类或结构的数据布局的性质,比如Auto、Explicit或sequential
ThreadStatic
Field(静态)
实现线程局部存储(TLS)。不能跨多个线程共享给定的静态字段,每个线程拥有这个静态字段的副本
 
下面介绍几种常用的属性
1.[STAThread]和[MTAThread]属性
class Class1
{
        [STAThread]
        Static void Main( string[] args )
        {
        }
}
使用STAThread属性将程序的默认线程模型指定为单线程模型。注意,线程模型只影响使用COM interop的应用程序,将这个属性应用于不使用COM interop的程序将不会产生任何效果。
2. AttributeUsage属性
        除了用于标注常规C#类型的自定义属性以外,还可以使用AttributeUsage属性定义你使用这些属性的方式。文件记录的AttributeUsage属性调用用法如下:
[AttributeUsage( validon , AllowMutiple = allowmutiple , Inherited = inherited )]
Validon参数是AttributeTargets类型的,这个枚举值的定义如下:
public enum AttributeTargets
{
        Assembly = 0x0001,
        Module = 0x0002,
        Class = 0x0004,
        Struct = 0x0008,
        Enum = 0x0010,
        Constructor = 0x0020,
        Method = 0x0040,
        Property = 0x0080,
        Field = 0x0100,
        Event = 0x200,
        Interface = 0x400,
        Parameter = 0x800,
        Delegate = 0x1000,
        All = Assembly | Module | Class | Struct | Enum | Constructor| Method | Property|                    Filed| Event| Interface | Parameter | Deleagte ,
        ClassMembers = | Class | Struct | Enum | Constructor | Method | Property | Field |                    Event | Delegate | Interface
}
AllowMultiple决定了可以在单个字段上使用某个属性多少次,在默认情况下,所有的属性都是单次使用的。示例如下:
[AttributeUsage( AttributeTargets.All , AllowMultiple = true )]
public class SomethingAttribute : Attribute
{
        public SomethingAttribute( string str )
        {
    

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap