C#中的一些常用属性
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)。
 
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号