欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中Property和Attribute的區(qū)別實例詳解

 更新時間:2015年06月02日 11:41:16   作者:春哥也編程  
這篇文章主要介紹了C#中Property和Attribute的區(qū)別,較為詳細的分析了C#中Property和Attribute的功能、定義、區(qū)別及使用時的相關(guān)注意事項,需要的朋友可以參考下

本文實例分析了C#中Property和Attribute的區(qū)別。分享給大家供大家參考。具體分析如下:

在C#中有兩個屬性,分別為Property和Attribute,兩個的中文意思都有特性、屬性之間,但是用法上卻不一樣,為了區(qū)別,本文暫把Property稱為特性,把Attribute稱為屬性。

Attribute才是本文的主角,把它稱為屬性我覺得很恰當(dāng)。屬性的意思就是附屬于某種事物上的,用來說明這個事物的各種特征的一種描述。而Attribute就是干這事的。它允許你將信息與你定義的C#類型相關(guān)聯(lián),作為類型的標(biāo)注。這些信息是任意的,就是說,它不是由語言本身決定的,你可以隨意建立和關(guān)聯(lián)任何類型的任何信息。你可以作用屬性定義設(shè)計時信息和運行時信息,甚至是運行時的行為特征。關(guān)鍵在于這些信息不僅可以被用戶取出來作為一種類型的標(biāo)注,它更可以被編譯器所識別,作為編譯時的一種附屬條件參加程序的編譯。

以下部分內(nèi)容及代碼來源于《C#技術(shù)揭秘》(Inside C# Sencond Edition)

定義屬性:

屬性實際上是一個派生自System.Attribute基類的類。System.Attribute類含有幾個用于訪問和檢查自定義屬性的方法。盡管你有權(quán)將任何類定義為屬性,但是按照慣例來說,從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; }
   }
}

我們在這里添加了不同注冊表的枚舉、屬性類的構(gòu)造器以及兩個特性(Property)。在定義屬性時你可以做許許多多的事情,下面我們看看如何在運行時查詢屬性。要想在運行時查詢類型或成員所附著的屬性,必須使用反射

查詢類屬性:

假設(shè)你希望定義一個屬性,這個屬性定義了將在其上創(chuàng)建對象的遠程服務(wù)器。如果沒有這個屬性,就要把此信息保存在一個常量中或是一個應(yīng)用程序的資源文件中。通過使用屬性,只需用以下方法標(biāo)注出類的遠程服務(wù)器名即可:

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();
   }
  }
}

運行結(jié)果為:

Creat this object on COSETTE。

注意:在這個例子中的屬性類名具有Attribute后綴。但是,當(dāng)我們將此屬性附著給類型或成員時卻不包括Attribute后綴。這是C#語言的設(shè)計者提供的簡單方式。當(dāng)編譯器看到一個屬性被附著給一個類型或成員時,它會搜索具有指定屬性名的System.Attribute派生類。如果編譯器沒有找到匹配的類,它就在指定的屬性名后面加上Attribute,然后再進行搜索。因此,常見的使用做法是將屬性類名定義為以Attribute結(jié)尾,在使用時忽略名稱的這一部分。以下的代碼都采用這種命名方式。

查詢方法屬性:

在下面這個例子中,我們使用屬性將方法定義為可事務(wù)化的方法,只要存在TransactionableAttribute屬性,代碼就知道具有這個屬性的方法可以屬于一個事務(wù)。

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();
   }
  }
}

運行結(jié)果如下:

Foo is transactionable.
Goo is transactionable.
 
查詢字段屬性:

假設(shè)有一個類含有一些字段,我們希望將它們的值保存進注冊表。為此,可以使用以枚舉值和字符串為參數(shù)的構(gòu)造器定義一個屬性,這個枚舉值代表正確的注冊表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();
   }
  }
}

運行結(jié)果為:

Foo will be saved in HKEY_CURRENT_USER\\Foo

大家可以看到,用屬性來標(biāo)注類、方法、字段,既可以把用戶的自定義信息附屬在實體上,又可以在運行時動態(tài)的查詢。下面我將講一些C#中默認(rèn)的預(yù)定義屬性,見下表:

預(yù)定義的屬性 有效目標(biāo) 說明
AttributeUsage Class 指定另一個屬性類的有效使用方式
CLSCompliant 全部 指出程序元素是否與CLS兼容
Conditional Method 指出如果沒有定義相關(guān)聯(lián)的字符串,編譯器就可以忽略對這個方法的任何調(diào)用
DllImport Method 指定包含外部方法的實現(xiàn)的DLL位置
STAThread Method(Main) 指出程序的默認(rèn)線程模型為STA
MTAThread Method(Main) 指出程序的默認(rèn)模型為多線程(MTA)
Obsolete 除了Assembly、Module、Parameter和Return 將一個元素標(biāo)示為不可用,通知用戶此元素將被從未來的產(chǎn)品
ParamArray Parameter 允許單個參數(shù)被隱式地當(dāng)作params(數(shù)組)參數(shù)對待
Serializable Class、Struct、enum、delegate 指定這種類型的所有公共和私有字段可以被串行化
NonSerialized Field 應(yīng)用于被標(biāo)示為可串行化的類的字段,指出這些字段將不可被串行化
StructLayout Class、struct 指定類或結(jié)構(gòu)的數(shù)據(jù)布局的性質(zhì),比如Auto、Explicit或sequential
ThreadStatic Field(靜態(tài)) 實現(xiàn)線程局部存儲(TLS)。不能跨多個線程共享給定的靜態(tài)字段,每個線程擁有這個靜態(tài)字段的副本

下面介紹幾種常用的屬性

1.[STAThread]和[MTAThread]屬性

class Class1
{
  [STAThread]
  Static void Main( string[] args )
  {
  }
}

使用STAThread屬性將程序的默認(rèn)線程模型指定為單線程模型。注意,線程模型只影響使用COM interop的應(yīng)用程序,將這個屬性應(yīng)用于不使用COM interop的程序?qū)⒉粫a(chǎn)生任何效果。

2. AttributeUsage屬性

除了用于標(biāo)注常規(guī)C#類型的自定義屬性以外,還可以使用AttributeUsage屬性定義你使用這些屬性的方式。文件記錄的AttributeUsage屬性調(diào)用用法如下:

[AttributeUsage( validon , AllowMutiple = allowmutiple , Inherited = inherited )]
Validon參數(shù)是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決定了可以在單個字段上使用某個屬性多少次,在默認(rèn)情況下,所有的屬性都是單次使用的。示例如下:

[AttributeUsage( AttributeTargets.All , AllowMultiple = true )]
public class SomethingAttribute : Attribute
{
  public SomethingAttribute( string str )
  {
  }
}
//如果AllowMultiple = false , 此處會報錯
[Something(“abc”)]
[Something(“def”)]
class Myclass
{
}

Inherited參數(shù)是繼承的標(biāo)志,它指出屬性是否可以被繼承。默認(rèn)是false。
Inherited AllowMultiple 結(jié)果
true false 派生的屬性覆蓋基屬性
true false 派生的屬性和基屬性共存

代碼示例:

using System;
using System.Reflection;
namespace AttribInheritance
{
  [AttributeUsage(
   AttributeTargets.All,
   AllowMultiple=true,
//  AllowMultiple=false,
   Inherited=true
  )]
  public class SomethingAttribute : Attribute
  {
   private string name;
   public string Name
   {
    get { return name; }
    set { name = value; }
   }
   public SomethingAttribute(string str)
   {
    this.name = str;
   }
  }
  [Something("abc")]
  class MyClass
  {
  }
  [Something("def")]
  class Another : MyClass
  {
  }
  class Test
  {
   [STAThread]
   static void Main(string[] args)
   {
    Type type =
     Type.GetType("AttribInheritance.Another");
    foreach (Attribute attr in
     type.GetCustomAttributes(true))
//    type.GetCustomAttributes(false))
    {
     SomethingAttribute sa =
      attr as SomethingAttribute;
     if (null != sa)
     {
     Console.WriteLine(
       "Custom Attribute: {0}",
       sa.Name);
     }
    }
 
   }
  }
}

當(dāng)AllowMultiple被設(shè)置為false時,結(jié)果為:
Custom Attribute : def
當(dāng)AllowMultiple被設(shè)置為true時,結(jié)果為:
Custom Attribute : def
Custom Attribute : abc

注意,如果將false傳遞給GetCustomAttributes,它不會搜索繼承樹,所以你只能得到派生的類屬性。
 
3.Conditional 屬性

你可以將這個屬性附著于方法,這樣當(dāng)編譯器遇到對這個方法調(diào)用時,如果沒有定義對應(yīng)的字符串值,編譯器就忽略這個調(diào)用。例如,以下方法是否被編譯取決于是否定義了字符串“DEGUG”:

[Condition(“DEBUG”) ]
public void SomeDebugFunc()
{
  Console.WriteLine(“SomeDebugFunc”);
}
using System;
using System.Diagnostics;
namespace CondAttrib
{
  class Thing
  {
   private string name;
   public Thing(string name)
   {
    this.name = name;
    #if DEBUG
     SomeDebugFunc();
    #else
     SomeFunc();
    #endif
   }
   public void SomeFunc()
    { Console.WriteLine("SomeFunc"); }
   [Conditional("DEBUG")]
   [Conditional("ANDREW")]
   public void SomeDebugFunc()
    { Console.WriteLine("SomeDebugFunc"); }
  }
  public class Class1
  {
   [STAThread]
   static void Main(string[] args)
   {
    Thing t = new Thing("T1");
   }
  }
}

4. Obsolete 屬性

隨著代碼不斷的發(fā)展,你很可以會有一些方法不用??梢詫⑺鼈兌紕h除,但是有時給它們加上適當(dāng)?shù)臉?biāo)注比刪除它們更合適,例如:

using System;
namespace ObsAttrib
{
  class SomeClass
  {
   [Obsolete("Don't use OldFunc, use NewFunc instead", true)]
   public void OldFunc( ) { Console.WriteLine("Oops"); }
 
   public void NewFunc( ) { Console.WriteLine("Cool"); }
  }
  class Class1
  {
   [STAThread]
   static void Main(string[] args)
   {
    SomeClass sc = new SomeClass();
    sc.NewFunc();
//   sc.OldFunc(); // compiler error
   }
  }
}

我們將Obsolete屬性的第二個參數(shù)設(shè)置為true,當(dāng)調(diào)用時函數(shù)時編譯器會產(chǎn)生一個錯誤。

E:\InsideC#\Code\Chap06\ObsAttrib\ObsAttrib\Class1.cs(20): 'ObsAttrib.SomeClass.OldFunc()' 已過時: 'Don't use OldFunc, use NewFunc instead'
 
5. DllImport和StructLayout屬性

DllImport可以讓C#代碼調(diào)用本機代碼中的函數(shù),C#代碼通過平臺調(diào)用(platform invoke)這個運行時功能調(diào)用它們。

如果你希望運行時環(huán)境將結(jié)構(gòu)從托管代碼正確地編組現(xiàn)非托管代碼(或相反),那么需要為結(jié)構(gòu)的聲明附加屬性。為了使結(jié)構(gòu)參數(shù)可以被正確的編組,必須使用StructLayout屬性聲明它們,指出數(shù)據(jù)應(yīng)該嚴(yán)格地按照聲明中列出的樣子進行布局。如果不這么做,數(shù)據(jù)將不能正確地被編組,而應(yīng)用程序可能會出錯。

using System;
using System.Runtime.InteropServices; // for DllImport
namespace nativeDLL
{
  public class Test
  {
//  [DllImport ("user32.dll")] // all the defaults are OK
   [DllImport("user32", EntryPoint="MessageBoxA",
    SetLastError=true,
    CharSet=CharSet.Ansi, ExactSpelling=true,
    CallingConvention=CallingConvention.StdCall)]
   public static extern int MessageBoxA (
    int h, string m, string c, int type);
   [StructLayout(LayoutKind.Sequential)]
   public class SystemTime {
    public ushort wYear;
    public ushort wMonth;
    public ushort wDayOfWeek;
    public ushort wDay;
    public ushort wHour;
    public ushort wMinute;
    public ushort wSecond;
    public ushort wMilliseconds;
   }
   [DllImport ("kernel32.dll")]
   public static extern void GetLocalTime(SystemTime st);
   [STAThread]
   public static void Main(string[] args)
   {
    MessageBoxA(0, "Hello World", "nativeDLL", 0);
    SystemTime st = new SystemTime();
    GetLocalTime(st);
    string s = String.Format("date: {0}-{1}-{2}",
     st.wMonth, st.wDay, st.wYear);
    string t = String.Format("time: {0}:{1}:{2}",
     st.wHour, st.wMinute, st.wSecond);
    string u = s + ", " + t;
    MessageBoxA(0, u, "Now", 0);
   }
  }
}

6. 配件屬性

當(dāng)使用.NET產(chǎn)生任何類型的C#工程時,會自動的產(chǎn)生一個AssemblyInfo.cs源代碼文件以及應(yīng)用程序源代碼文件。AssemblyInfo.cs中含有配件中代碼的信息。其中的一些信息純粹是信息,而其它信息使運行時環(huán)境可以確保惟一的命名和版本號,以供重用你的配件的客戶代碼使用。
 
7. 上下文屬性

.NET柜架還提供了另一種屬性:上下文屬性。上下文屬性提供了一種截取機制,可以在類的實例化和方法調(diào)用之前和之后進行處理。這種功能用于對象遠程調(diào)用,它是從基于COM的系統(tǒng)所用的COM+組件服務(wù)和Microsoft Transaction Services(MTS)。

希望本文所述對大家的C#程序設(shè)計有所幫助。

相關(guān)文章

  • Response.Redirect 正在中止線程解決方案

    Response.Redirect 正在中止線程解決方案

    這兩天在開發(fā)調(diào)試過程中,老是會出現(xiàn)在一個 "正在中止線程“(ThreadAbortException)的例外信息,很是疑惑,于是網(wǎng)上收集整理了一下,現(xiàn)在曬出來和大家分享,希望對你們有幫助
    2012-11-11
  • 最新評論