标题: 转 区别C#中的两个属性(Property和Attribute)
- Winner.Net(2007) 2008-02-20 22:25 阅读:211
- 评论:0 | 添加评论
区别C#中的两个属性(Property和Attribute)
                        区别C#中的两个属性(Property和Attribute)
        在C#中有两个属性,分别为Property和Attribute,两个的中文意思都有特性、属性之间,但是用法上却不一样,为了区别,本文暂把Property称为特性,把Attribute称为属性。
        Property比较简单,就是我们常用的get和set,主要用于为类中的private和protected变量提供读取和设置的接口。关于Property请参看我的一篇文章:
        http://blog.csdn.net/tjvictor/archive/2006/06/23/824617.aspx
        Attribute才是本文的主角,把它称为属性我觉得很恰当。属性的意思就是附属于某种事物上的,用来说明这个事物的各种特征的一种描述。而Attribute就是干这事的。它允许你将信息与你定义的C#类型相关联,作为类型的标注。这些信息是任意的,就是说,它不是由语言本身决定的,你可以随意建立和关联任何类型的任何信息。你可以作用属性定义设计时信息和运行时信息,甚至是运行时的行为特征。关键在于这些信息不仅可以被用户取出来作为一种类型的标注,它更可以被编译器所识别,作为编译时的一种附属条件参加程序的编译。
        以下部分内容及代码来源于《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)。在定义属性时你可以做许许多多的事情,下面我们看看如何在运行时查询属性。要想在运行时查询类型或成员所附着的属性,必须使用反射,请参见我的另一篇关于反射的简单文章
     http://blog.csdn.net/tjvictor/archive/2007/01/24/1492079.aspx
查询类属性:
        假设你希望定义一个属性,这个属性定义了将在其上创建对象的远程服务器。如果没有这个属性,就要把此信息保存在一个常量中或是一个应用程序的资源文件中。通过使用属性,只需用以下方法标注出类的远程服务器名即可:
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(数组)参数对待
添加评论
返回顶部 | 返回首页