程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#中Property和Attribute的差別實例詳解

C#中Property和Attribute的差別實例詳解

編輯:C#入門知識

C#中Property和Attribute的差別實例詳解。本站提示廣大學習愛好者:(C#中Property和Attribute的差別實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C#中Property和Attribute的差別實例詳解正文


本文實例剖析了C#中Property和Attribute的差別。分享給年夜家供年夜家參考。詳細剖析以下:

在C#中有兩個屬性,分離為Property和Attribute,兩個的中辭意思都有特征、屬性之間,然則用法上卻紛歧樣,為了差別,本文暫把Property稱為特征,把Attribute稱為屬性。

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)。在界說屬性時你可以做許很多多的工作,上面我們看看若何在運轉時查詢屬性。要想在運轉時查詢類型或成員所附著的屬性,必需應用反射

查詢類屬性:

假定你願望界說一個屬性,這個屬性界說了將在其上創立對象的長途辦事器。假如沒有這個屬性,就要把此信息保留在一個常量中或是一個運用法式的資本文件中。經由過程應用屬性,只需用以下辦法標注出類的長途辦事器名便可:

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 )
  {
  }
}
//假如AllowMultiple = false , 此處會報錯
[Something(“abc”)]
[Something(“def”)]
class Myclass
{
}

Inherited參數是繼續的標記,它指出屬性能否可以被繼續。默許是false。
Inherited AllowMultiple 成果
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);
     }
    }
 
   }
  }
}

當AllowMultiple被設置為false時,成果為:
Custom Attribute : def
當AllowMultiple被設置為true時,成果為:
Custom Attribute : def
Custom Attribute : abc

留意,假如將false傳遞給GetCustomAttributes,它不會搜刮繼續樹,所以你只能獲得派生的類屬性。
 
3.Conditional 屬性

你可以將這個屬性附著於辦法,如許當編譯器碰到對這個辦法挪用時,假如沒有界說對應的字符串值,編譯器就疏忽這個挪用。例如,以下辦法能否被編譯取決因而否認義了字符串“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 屬性

跟著代碼赓續的成長,你很可以會有一些辦法不消。可以將它們都刪除,然則有時給它們加上恰當的標注比刪除它們更適合,例如:

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屬性的第二個參數設置為true,當挪用時函數時編譯器會發生一個毛病。

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

DllImport可讓C#代碼挪用本機代碼中的函數,C#代碼經由過程平台挪用(platform invoke)這個運轉時功效挪用它們。

假如你願望運轉時情況將構造從托管代碼准確地編組現非托管代碼(或相反),那末須要為構造的聲明附加屬性。為了使構造參數可以被准確的編組,必需應用StructLayout屬性聲明它們,指出數據應當嚴厲地依照聲明中列出的模樣停止結構。假如不這麼做,數據將不克不及准確地被編組,而運用法式能夠會失足。

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. 配件屬性

當應用.NET發生任何類型的C#工程時,會主動的發生一個AssemblyInfo.cs源代碼文件和運用法式源代碼文件。AssemblyInfo.cs中含有配件中代碼的信息。個中的一些信息純潔是信息,而其它信息使運轉時情況可以確保唯一的定名和版本號,以供重用你的配件的客戶代碼應用。
 
7. 高低文屬性

.NET櫃架還供給了另外一種屬性:高低文屬性。高低文屬性供給了一種截取機制,可以在類的實例化和辦法挪用之前和以後停止處置。這類功效用於對象長途挪用,它是從基於COM的體系所用的COM+組件辦事和Microsoft Transaction Services(MTS)。

願望本文所述對年夜家的C#法式設計有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved