乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C#基礎全接觸

       hbezgdmm 2010-09-11

      靜態(tài)方法只能訪問類中的靜態(tài)成員。
      構造函數(shù)和析構函數(shù)不能被繼承。
      在派生類中覆蓋基類中的方法時,在方法前面加上new關鍵字可關閉編譯器的警告。
      base關鍵字主要是為派生類調用基類成員提供一個簡寫的方法。
      C#中的多態(tài)性有兩種:編譯時的多態(tài)性和運行時的多態(tài)性;編譯時的多態(tài)性是通過重載實現(xiàn)的,運行時的多態(tài)性是通過虛成員實現(xiàn)的;編譯時的多態(tài)性為我們提供了運行速度快的特點,而運行時的多態(tài)性則帶來了高度的靈活和抽象的特點。
      方法在使用了virtual修飾符之后,不允許再有static,abstract或override修飾符。
      在派生類中聲明對虛方法的重載,要求在聲明中加上override關鍵字,而且不能有new,static或virtual修飾符.
      抽象類只能作為其他類的基類,不能被實例化。
      抽象類中的抽象方法在派生類中不能使用base關鍵字來進行訪問。
      密封類(使用sealed修飾符的類)不能被其他類繼承。
      將方法密封可防止方法所在的類的派生類對該方法重載。
      是類的每個成員方法都可以作為密封方法,密封方法必須對基類的虛方法進行重載,提供具體的實現(xiàn)方法。

      引用類型是類型安全的指針,它們的內存是分配在堆(保存指針地址)上的。
      String、數(shù)組、類、接口和委托都是引用類型。
      強制類型轉換與as類型轉換的區(qū)別:當類型轉換非法時,強制類型轉換將拋出一個System.InvalidCastException異常,
      而as不會拋出異常,它返回一個null值。
      用using創(chuàng)建別名:using console = System.Console;
      訪問限定符:
      public  該成員可以被其他任何類訪問
      protected 該成員只能被其派生類訪問
      private  該成員只能被本類的其他成員訪問
      internal 該成員只能在當前編譯單元的其他成員訪問
      帶參數(shù)列表和返回值的Main方法:
      class Test
      {
        public static int Main(string[] args)
        {
          foreach (string arg in args)
          {
          ...
          }
        }
      }
      構造函數(shù)(constructor)包括實例構造函數(shù)和靜態(tài)構造函數(shù)。
      構造函數(shù)與類名相同,且不能有返回值。例:
      class TestClass
      {
        TestClass()  //實例構造函數(shù):可以訪問靜態(tài)成員和實例成員,用于初始化實例成員
        {
        ...
        }

        static TestClass() //靜態(tài)構造函數(shù):只能訪問靜態(tài)成員,用于初始化靜態(tài)成員
        {
        ...
        }
      }
      類的靜態(tài)成員屬于類所有,不必生成實例就可以訪問,它是在載入包含類的應用程序時創(chuàng)建的,
      但靜態(tài)方法不能訪問類的實例變量和方法。通常,靜態(tài)變量是在定義時就賦初始值的。
      類的實例成員屬于類的實例所有,不創(chuàng)建實例對象就無法對其進行訪問,實例成員可以訪問類的
      靜態(tài)成員和其它實例成員。
      調用基類的析構函數(shù):
      class A
      {
        public A()
        {
        ...
        }
      }
      class B
      {
        public B(): base()  //調用基類的析構函數(shù)
        {
        ...
        }
      }
      常量:其值是在編譯時設定的,必須是數(shù)值文字。默認狀態(tài)下常量是靜態(tài)的。例:
      class A
      {
        public const double pi = 3.1415;
      }
      常量是編譯時就確定的值,只讀字段是在運行才能確定的值。比如運行時才能確定的屏幕分辨率。
      只讀字段只能在類的析構函數(shù)中賦值。
      靜態(tài)只讀字段:
      class A
      {
        public static readonly int ScreenWidth;  //靜態(tài)只讀字段
        static A()   //靜態(tài)析構函數(shù)
        {
          ScreenWidth = 1024;  //在靜態(tài)析構函數(shù)中初始化
        }
      }
      在類的繼承中,類的析構函數(shù)是不會被繼承的。
      一個派生類只能從一個基類繼承,不能同時從多個基類繼承,但可以通過繼承多個接口來
      達到相同目的。實現(xiàn)多繼承的唯一方法就是使用接口。例:
      class MyFancyGrid: Control, ISerializable, IDataBound
      {
      ...
      }
      密封類是不能繼承的類,抽象類不能被定義為密封類,且密封類的私有成員不能用protected修飾,
      只能用private。例:
      sealed class A
      {
      ...
      }
      關鍵字ref和out用于指定用引用方式傳遞方法的參數(shù)。
      它們的區(qū)別是:ref參數(shù)必須初始化,而out參數(shù)不需要初始化。所以在方法處理代碼依賴參數(shù)的
      初始化值時使用ref,不依賴初始化值時使用out。
      對out參數(shù)即使在傳遞前對其進行了初始化,其值也不會傳遞到方法處理函數(shù)內部。傳遞時系統(tǒng)
      會將其設為未初始化。所以在方法內部必須對out參數(shù)進行初始化。
      方法重載時,必須參數(shù)數(shù)目和參數(shù)類型其中之一不同,返回值不同不能作為重載。
      C#不支持方法的默認值,只能通過方法重載來實現(xiàn)。例:
      class A
      {
        int Method(int a)
        {
        ...
        }

        void Method(int a, int b) //參數(shù)數(shù)目不同
        {    //返回值不同不能作為重載
        ...
        }
      }
      params參數(shù)用于一個不定數(shù)目參數(shù)的方法,一般后面跟一個數(shù)組。例:
      class A
      {
        public void Method(params int[] i)
        {
        ...
        }
      }
      方法的覆蓋:指派生類覆蓋基類的同名方法,有二種方法
      1)第一種是在派生類要覆蓋的方法前面加new修飾,而基類不需要作任何改動。
      這種方法的缺點是不能實現(xiàn)多態(tài)。例:
      class A
      {
        public void Method()  //無需任何修飾
        {
        ...
        }
      }

      class B: A   //從基類繼承
      {
        new public void Method() //覆蓋基類的同名方法
        {
        ...
        }
      }

      class TestClass
      {
        A Instance = new B();
        Instance.Method();  //這時將調用類A的Method方法,而不是類B的Method方法
      }

      2)第二種是在派生類要覆蓋的方法前面加override修飾,而基類的同名方法前面加virtual修飾。
      這樣就能實現(xiàn)多態(tài),例:

      class A
      {
        virtual public void Method()   //基類定義虛方法
        {      //虛擬方法不能定義為private,因為private成員對派生類是無法訪問的
        ...
        }
      }

      class B: A     //從基類繼承
      {
        override public void Method()   //派生類覆蓋基類的同名虛方法
        {
        ...
        }
      }

      class TestClass
      {
        protected void Test()
        {
          A Instance = new B();   //定義一個實例,類型為基類,從派生類創(chuàng)建
            //派生類總是能夠向上轉換為其基類
          Instance.Method();    //將調用派生類B的Method方法,而不是基類的,這就是多態(tài)
        }
      }

      說明:new修飾的方法覆蓋不能實現(xiàn)多態(tài)的原因,是因為使用new時編譯器只會實現(xiàn)早期綁定(early binding)。
      即調用的方法在編譯時就決定了:編譯器看到Instance.Method()而Instance的類是A,就會調用類A的Method()方法。
      override修飾的方法覆蓋可以實現(xiàn)多態(tài)的原因,是因為實現(xiàn)了后期綁定(late binding)。
      使用override時強制編譯器在運行時根據(jù)類的真正類型正確調用相應的方法,而不是在編譯時。
      而基類的同名方法必須加virtual修飾。
      類的靜態(tài)方法可能通過 類名.靜態(tài)方法名 這種格式來調用,不能使用 實例名.靜態(tài)方法名 這種方法調用。
      因為類的靜態(tài)方法為類所有(是屬于類本身的),而非實例所有(不是屬于類的實例的)。
      類的靜態(tài)方法可以訪問類的任何靜態(tài)成員,但不能訪問類的實例成員。
      C#中類的變量稱為字段。類的public變量稱為類的公共字段。
      類的屬性由一個protected(也可以是private)字段和getter和setter方法構成:
      class Address
      {
        protected string zipCode; //protected字段,注意大小寫
        public string ZipCode
        {
          get    //getter方法
          {
            return zipCode;
          }
          set    //setter方法
          {
            zipCode = value;  //被傳遞的值自動被在這個value變量中
          }
        };
      }
      只讀屬性是指省略setter方法的屬性,只讀屬性只能讀取,不能設置。
      屬性也可以用限定符virtual,override和abstract修飾,功能同其他類的方法。
      屬性有一個用處稱為懶惰的初始化(lazy initialization)。即在需要類成員時才對它們進行
      初始化。如果類中包含了很少被引用的成員,而這些成員的初始化又會花費大量的時候和系統(tǒng)
      資源的話,懶惰的初始化就很有用了。
      C#中數(shù)組對象共同的基類是System.Array。
      將數(shù)組聲明為類的一個成員時,聲明數(shù)組與實例化數(shù)組必須分開,這是因為只能在運行時創(chuàng)建了
      類的實例對象之后,才能實例化數(shù)組元素值。
      聲明:
      int[] intArray;  //一維數(shù)組
      int[,,] int3Array; //三維數(shù)組
      初始化:
      intArray = new int[3] {1,2,3};
      int[,] int2Array = new int[2,3] {{1,2,3},{4,5,6}}; //聲明時可以初始化
      遍歷:
      1)一維數(shù)組
      for (int i = 0; i < intArray.Length; i++); //Array.Length返回數(shù)組所有元素的個數(shù)
      foreach (int i in intArray);
      for (int i = 0; i < intArray.GetLength(0); i++);//Array.GetLength(0)返回數(shù)組第一維的個數(shù)
      2)多維數(shù)組
      for (int i = 0; i < int3Array.GetLength(0); i++) //遍歷三維數(shù)組
        for (int j = 0; j < int3Array.GetLength(1); j++)
          for (int k = 0; k < int3Array.GetLength(2); k++)
          {
          ...
          }
      數(shù)組的維數(shù)就是該數(shù)組的秩(Rank)。Array.Rank可以返回數(shù)據(jù)的秩。
      鋸齒數(shù)組(jagged Array)是元素為數(shù)組的數(shù)組,例:
      int[][] jaggedArray = new int[2][]; //包含二個元素,每個元素是個數(shù)組
      jaggedArray[0] = new int[2];  //每個元素必須初始化
      jaggedArray[1] = new int[3];
      for (int i = 0; i < jaggedArray.Length; i++) //遍歷鋸齒數(shù)組
        for (int j = 0; j < jaggedArray[i].Length; j++)
        {
        ...
        }
      類的屬性稱為智能字段,類的索引器稱為智能數(shù)組。由于類本身作數(shù)組使用,所以用
      this作索引器的名稱,索引器有索引參數(shù)值。例:
      using System;
      using System.Collections;
      class MyListBox
      {
        protected ArrayList data = new ArrayList();
        public object this[int idx]  //this作索引器名稱,idx是索引參數(shù)
        {
          get
          {
            if (idx > -1 && idx < data.Count)
            {
              return data[idx];
            }
            else
            {
              return null;
            }
          }
          set
          {
            if (idx > -1 && idx < data.Count)
            {
              data[idx] = value;
            }
            else if (idx = data.Count)
            {
              data.Add(value);
            }
            else
            {
              //拋出一個異常
            }
          }
        }
      }
      接口是二段不同代碼之間約定,通過約定實現(xiàn)彼此之間的相互訪問。
      C#并不支持多繼承,但通過接口可實現(xiàn)相同功能。
      當在接口中指定了實現(xiàn)這個接口的類時,我們就稱這個類“實現(xiàn)了該接口”或“從接口繼承”。
      一個接口基本上就是一個抽象類,這個抽象類中除了聲明C#類的其他成員類型——例如屬性、
      事件和索引器之外,只聲明了純虛擬方法。
      接口中可以包含方法、屬性、索引器和事件——其中任何一種都不是在接口自身中來實現(xiàn)的。例:
      interface IExampleInterface
      {
        //property declaration
        int testProperty { get; }

        //event declaration
        event testEvevnt Changed;

        //mothed declaration
        function void testMothed();

        //indexer declaration
        string this[int index] { get; set; }
      }
      說明:定義接口時,在方法、屬性、事件和索引器所有這些接口成員都不能用public之類的訪問限定符,
      因為所有接口成員都是public類型的。
      因為接口定義了一個約定,任何實現(xiàn)一個接口的類都必須定義那個接口中每一個成員,否則將編譯失敗。例:
      using System;
      public class FancyControl
      {
        protected string data;
        public string Data
        {
          get {return this.data;}
          set {data = value;}
        }
      }

      interface IValidate
      {
        bool Validate(); //接口方法
      }

      public class MyControl: FancyControl, IValidate
      {
        public MyControl()
        {
          data = "my control data";
        }

        public bool Validate()  //實現(xiàn)接口
        {
          if (data == "my control data")
            return true;
          else
            return false;
        }
      }
      class InterfaceApp
      {
        MyControl myControl = new MyControl();
       
        IValidate val = (IValidate)myControl;  //可以將一個實現(xiàn)某接口的類,轉換成該接口
        bool success = val.Validate();  //然后可調用該接口的方法
      }
      也可以用:
      bool success = myControl.Validate();
      這種方法來調用Validate方法,因為Validate在類MyControl中是被定義成public的,如果去除public,Validate方法被隱藏,
      就不能用這種方法調用了,這樣隱藏接口方法稱為名字隱藏(name hiding)。
      可以用:類實例 is 接口名 來判斷某個類是否實現(xiàn)了某接口,例:
      myControl is IValidate  //MyControl類的實例myControl是否實現(xiàn)了IValidate接口
      當然,也可用as來作轉換,根據(jù)轉換結果是否為null來判斷某個類是否實現(xiàn)了某接口,例:
      IValidate val = myControl as IValidate;
      if (null == val)
      {
      ...  //沒有實現(xiàn)IValidate接口
      }
      else
      {
      ...  //實現(xiàn)了IValidate接口
      }

      如果一個類從多個接口繼承,而這些接口中如果定義的同名的方法,則實現(xiàn)接口的方法時,必須加接口名來區(qū)別,
      寫成 接口名.方法名。假設Test類從IDataStore和ISerializable二個接口繼承,而這二個接口都有SaveData()方法,
      實現(xiàn)SaveData()方法時必須寫成:
      class Test: ISerializable, IDataStore
      {
        void ISerializable.SaveData()
        {
        ...
        }

        void IDataStore.SaveData()
        {
        ...
        }
      }

      如果一個類從多個接口繼承,為了方便可以定義一個新的接口,這個接口繼續(xù)多個接口,然后類直接從這個接口繼承就
      可以了,這個叫合并接口。例:
      interface ISaveData: ISerializable, IDataStore
      {  //不需要定義任何方法或成員,只是用作合并
      }
      class Test: ISaveData  //只要繼承ISaveData就可以了
      {
      ...
      }
      C# 操作符優(yōu)先級(從高到低)
      初級操作符 () x.y f(x) a[x] x++ x-- new typeof sizeof checked unchecked
      一元操作符 + - | ~ ++x --x (T)x
      乘除操作符 * / %
      加減操作符 + -
      位移操作符 << >>
      關系操作符 < > <= >= is
      等于操作符 ==
      邏輯與  &
      邏輯異或 ^
      邏輯或  |
      條件與  &&
      條件或  ||
      條件操作符 ?:
      賦值操作符 = *= /= %= += -= <<= >>= &= ^= |=
      所有的二元操作符除賦值符外都是左聯(lián)合的,即從左到右計算。
      typeof()運算符可以從一個類名得到一個System.Type對象,而從System.Object對象繼承來的GetType()方法
      則可從一個類實例來得到一個System.Type對象。例:
      Type t1 = typeof(Apple); //Apple是一個類名
      Apple apple = new Apple(); //apple是Apple類的一個實例
      Type t2 = apple.GetType(); //t1與t2是相同的
      通過反射得到一個類的所有成員和方法:
      Type t = typeof(Apple);
      string className = t.ToString(); //得到類名
      MethodInfo[] methods = t.GetMethods(); //得到所有方法
      foreach (MethodInfo method in methods)
      {
      //用method.ToString()得到方法名
      }
      MemberInfo[] members = t.GetMembers(); //得到所有成員
      foreach (MemberInfo member in members)
      {
      //用member.ToString()得到成員名
      }
      sizeof()操作符用來計算值類型變量在內存中占用的字節(jié)數(shù)(Bytes),并且它只能在unsafe(非安全)
      代碼中使用。例:
      static unsafe public void ShowSizes()
      {
        int i, j;
        j = sizeof(short);
        j = sizeof(i);
      }
      盡可能使用復合賦值操作符,它比不用復合賦值操作符的效率高。
      for語句的語法為:
      for (initialization; Boolean-expression; step)
        embedded-statement
      在initialization和step部份還可以使用逗號操作符,例:
      for (int i = '0', j = 1; i <= '\xFF'; i++, j++)
      for (int i = 1, j = 1; i < 1000; i += j, j = i - j) //輸出斐波那契數(shù)列
       Console.Write("{0} ", i);
      在switch語句中執(zhí)行一個分支的代碼后還想執(zhí)行另一個分支的代碼,可以用:
      goto case 分支;
      操作符重載是為了讓程序更加自然,容易理解。想要為一個類重新定義一個操作符,使用以下語法:
      public static 返回值 operator 操作符 (操作對象1[,操作對象2])
      說明:
      1)所有重載的操作符方法都必須定義為public和static
      2)從技術上說返回值可以是任何類型,但通常是返回所定義方法使用的類型
      3)操作對象的數(shù)目取決于重載是一元操作符還是二元操作符,一元操作符只要一個操作對象,二元操作符則需要二個。
      4)不管重載是一元操作符還是二元操作符,第一個操作對象的類型都必須與返回值的類型一致;而對于二元操作符的第二個
      操作對象的類型則可以是任何類型。
      5)只有下列操作符可以被重載:
      一元:+ - ! ~ ++ -- true false
      二元:+ - * / % & | ^ << >> == != > < >= <=
      賦值操作符(+=,-=,*-,/=,%=等等)無法被重載。
      []和()操作符也無法被重載。
      6)操作符的優(yōu)先級是無法改變的,運算優(yōu)先級的規(guī)則是靜態(tài)的。

      例:假設一個Invoice發(fā)票類由多個InvoiceDetailLine類(成員只有一個Double類型的Amount金額屬性)組成,
      我們重載+操作符,使之可以將InvoiceDetailLine類的內容(注意不是金額合計)加在一起。
      class Invoice
      {
        public ArrayList DetailLine;
       
        public Invoice   //類的析構函數(shù)
        {
          DetailLine = new ArrayList(); //ArrayList存放多個InvoiceDetailLine類的實例
        }

        public static Invoice operator+ (Invoice Invoice1, Invoice Invoice2) //參數(shù)與返回值的類型一致
        {
          //Invoice1與Invoice2的內容合并
          Invoice ReturnInvoice = new Invoice();
          foreach(InvoiceDetailLine detailLine in Invoice1.DetailLines)
            ReturnInvoice.DetailLine.Add(detailLine);
          foreach(InvoiceDetailLine detailLine in Invoice2.DetailLines)
            ReturnInvoice.DetailLine.Add(detailLine);
          return ReturnInvoice;
        }
      }

      class InvoiceAddApp  //調用示例
      {
        public static void main()
        {
          Invoice i1 = new Invoice();
          for(int i = 0; i < 3; i++)
            i1.DetailLine.Add(new InvoiceDetailLine(i + 1));

          Invoice i2 = new Invoice();
          for(int i = 0; i < 3; i++)
            i2.DetailLine.Add(new InvoiceDetailLine(i + 1));

          Invoice summaryInvoice = i1 + i2;  //調用重載的操作符+方法
        }
      }


      自定義類型轉換可以編寫代碼實際二個不同的類、結構體之間的轉換。
      語法:public static implicite/explicite operator 輸出類型 (輸入類型)
      說明:
      1)轉換方法必須是靜態(tài)的。
      2)implicite表示隱式轉換,explicite表示顯式轉換。
      3)輸入類型和輸出類型其中之一必須與包含轉換的類或結構體類型。即轉換必須與本類相關。
      例:
      struct Celisus
      {
        public float t;

        public Celisus(float t)
        {
          this.t = t;   //this.t是結構體的字段,t是參數(shù)
        }

        public static implicite operator Celisus(float t) //float=>Celisus
        {
          return new Celisus(t);
        }

        public static implicite operator float(Celisus c) //Celisus=>float
        {
          return ((c.t - 32) / 9) * 5;
        }
      }


      代表的(delegate)目的與C++中的函數(shù)指針相同,代表不是在編譯時被定義的,而是在運行時被定義的。
      代表主要有二個用途:回調(Callback)和事件處理(event)
      回調通常用于異步處理和自定義處理。例:
      class DBManager
      {
        static DBConnection[] activeConnections;
        //聲明回調函數(shù)
        public void delegate EnumConnectionCallback(DBConnection connection);

        public static void EnumConnections(EnumConnectionCallback callback)
        {
          foreach (DBConnection connection in activeConnections)
          {
            callback(connection);  //執(zhí)行回調函數(shù)
          }
        }
      }

      //調用
      class DelegateApp
      {
        public static void ActiveConncetionCallback(DBConnection connection) //處理函數(shù)
        {
        ...
        }

        public void main()
        {
          //創(chuàng)建指向具體處理函數(shù)的代表實例(新建一個代表,讓它指向具體的處理函數(shù))
          DBManager.EmnuConnectionCallback myCallback = new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
          DBManager.EnumConnections(myCallback);
        }
      }

      //使用靜態(tài)代表,上面的調用改為
      class DelegateApp
      {
        //創(chuàng)建一個指向處理函數(shù)的靜態(tài)代表
        public static DBManager.EmnuConnectionCallback myCallback
          = new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
        public static void ActiveConncetionCallback(DBConnection connection)
        {
        ...
        }

        public void main()
        {
          DBManager.EnumConnections(myCallback);
        }
      }

      //在需要時才創(chuàng)建代表,上面的調用改為
      class DelegateApp
      {
        //將創(chuàng)建代表放在屬性的getter方法中
        public static DBManager.EmnuConnectionCallback myCallback
        {
          get
          {
            retun new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
          }
        }
        public static void ActiveConncetionCallback(DBConnection connection)
        {
        ...
        }

        public void main()
        {
          DelegateApp app = new DelegateApp(); //創(chuàng)建應用程序
          DBManager.EnumConnections(myCallback);
        }
      }


      可以將多個代表整合成單個代表,例:
      class CompositeDelegateApp
      {
        public static void LogEvent(Part part)
        {
        ...
        }

        public static void EmailPurchasingMgr(Part part)
        {
        ...
        }

        public static void Main()
        {
          //定義二個代表
          InventoryManager.OutOfStockExceptionMethod LogEventCallback
            = new InventoryManager.OutOfStockExceptionMethod(LogEvent);
          InventoryManager.OutOfStockExceptionMethod EmailPurchasingMgrCallback
            = new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);
          //整合為一個代表,注意后加的代表先執(zhí)行(這里是先執(zhí)行LogEventCallback)
          InventoryManager.OutOfStockExceptionMethod onHandExceptionEventsCallback
            = EmailPurchasingMgrCallback + LogEventCallback;
          //調用代表
          InventoryManager mgr = new InventoryManager();
          mgr.ProcessInventory(onHandExceptionEventsCallback);
          //InventoryManager類的ProcessInventory方法的原型為:
          //public void ProcessInventory(OutOfStockExceptionMethod exception);
        }
      }

      可以根據(jù)需要將多個代表自由地組合成單個代表,例:
      class CompositeDelegateApp
      {
        //代表指向的處理函數(shù)(三個代表三個函數(shù))
        public static void LogEvent(Part part)
        {
        ...
        }

        public static void EmailPurchasingMgr(Part part)
        {
        ...
        }

        public static void EmailStoreMgr(Part part)
        {
        ...
        }

        public static void Main()
        {
          //通過數(shù)組定義三個代表
          InventoryManager.OutOfStockExceptionMethod[] exceptionMethods
            = new InventoryManager.OutOfStockExceptionMethod[3];
          exceptionMethods[0] = new InventoryManager.OutOfStockExceptionMethod(LogEvent);
          exceptionMethods[1] = new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);
          exceptionMethods[2] = new InventoryManager.OutOfStockExceptionMethod(EmailStoreMgr);

          int location = 1;
          //再定義一個代表(用于組合成單代表)
          InventoryManager.OutOfStockExceptionMethod compositeDelegate;
          //根據(jù)需要組合
          if (location = 2)
          {
            compositeDelegate = exceptionMethods[0] + exceptionMethods[1];
          }
          else
          {
            compositeDelegate = exceptionMethods[0] + exceptionMethods[2];
          }
          //調用代表
          InventoryManager mgr = new InventoryManager();
          mgr.ProcessInventory(compositeDelegate);
        }
      }
      C#的事件遵循“發(fā)布——預訂”的設計模式。在這種模式中,一個類公布能夠出現(xiàn)的所有事件,
      然后任何的類都可以預訂這些事件。一旦事件產生,運行環(huán)境就負責通知每個訂戶事件已經發(fā)生了。
      當代表作為事件的處理結果時(或者說定義具有代表的事件),定義的代表必須指向二個參數(shù)的方法:
      一個參數(shù)是引發(fā)事件的對象(發(fā)布者),另一個是事件信息對象(這個對象必須從EventArgs類中派生)。
      例:
      using System;

      class InventoryChangeEventArgs: EventArgs //事件信息對象,從EventArgs類派生
      {
      ... //假設定義二個public屬性string Sku和int Change
      }

      class InventoryManager    //事件的發(fā)布者
      {
        //聲明代表
        public delegate void InventoryChangeEventHander(object source, InventoryChangeEventArgs e);
        //發(fā)布事件,event關鍵字可將一個代表指向多個處理函數(shù)
        public event InventoryChangeEventHandler onInventoryChangeHander;
       
        public void UpdateInventory(string sku, int change)
        {
          if (change == 0)
            return;
          InventoryChangeEventArgs e = new InventoryChangeEventArgs(sku, change);
          //觸發(fā)事件
          if (onInventoryChangeHandler != null) //如果有預訂者就觸發(fā)
            onInventoryChangeHandler(this, e); //執(zhí)行代表指向的處理函數(shù)
        }
      }

      class InventoryWatcher    //事件的預訂者
      {
        public InventoryWatcher(InventoryManager mgr) //mgr參數(shù)用于聯(lián)結發(fā)布者
        {
          this.inventoryManager = mgr;
          //預訂事件,用 += 調用多個處理函數(shù)
          mgr.onInventroyChangeHandler += new InventoryManager.InventoryChangeEventHandler(onInventoryChange);
          //事件處理函數(shù)
          void onInventroyChange(object source, InventroyChangeEventArgs e)
          {
          ...
          }

          InventoryManager inventoryManager;
        }
      }

      class EventsApp     //主程序
      {
        public static void Main()
        {
          InventoryManager inventoryManager = new InventoryManager();
          InventoryWatcher inventoryWatcher = new InventoryWatcher(inventoryManager);

          inventoryManager.UpdateInventory("111 006 116", -2);
          inventoryManager.UpdateInventory("111 006 116", 5);
        }
      }


      Microsoft Windows NT和IBM OS/2等操作系統(tǒng)都支持占先型多任務。在占先型多任務執(zhí)行中,處理器負責
      給每個線程分配一定量的運行時間——一個時間片(timeslice)。處理器接著在不同的線程之間進行切換,
      執(zhí)行相應的處理。在單處理器的計算機上,并不能真正實現(xiàn)多個線程的同時運行,除非運行在多個處理器
      的計算機上。操作系統(tǒng)調度的多線程只是根據(jù)分配給每個線程時間片進行切換執(zhí)行,感覺上就像同時執(zhí)行。

      上下文切換(context switching)是線程運行的一部分,處理器使用一個硬件時間來判斷一個指定線程的時間片
      何時結束。當這個硬件計時器給出中斷信號時,處理器把當前運行的線程所用的所有寄存器(registers)數(shù)據(jù)
      存儲到堆棧中。然后,處理器把堆棧里那些相同的寄存器信息存放到一種被稱為“上下文結構”的數(shù)據(jù)結構中。
      當處理器要切換回原來執(zhí)行的線程時,它反向執(zhí)行這個過程,利用與該線程相關的上下文結構,在寄存器里
      重新恢復與這一線程相關的信息。這樣的一個完整過程稱為“上下文切換”。

      多線程允許應用程序把任務分割為多個線程,它們彼此之間可以獨立地工作,最大限度地利用了處理器時間。

      using System;
      using System.Threading;

      class SimpleThreadApp
      {
        public static void WorkerThreadMethod() //線程的執(zhí)行體
        {
        ...      //執(zhí)行一些操作
        }

        public static void Main()
        {
          //創(chuàng)建一個線程代表指向線程的執(zhí)行體,ThreadStart是創(chuàng)建新線程必須用到的代表
          ThreadStart worker = new ThreadStart(WorkerThreadMethod);
          Thread t = new Thread(worker);  //用線程代表創(chuàng)建線程
          t.Start();     //執(zhí)行線程
        }
      }

      可以通過兩種方式來得到一個Thread對象:一種是通過創(chuàng)建一個新線程來得到,如上例;另一種在正在執(zhí)行的線程調用
      靜態(tài)的Thread.CurrentThread方法。
      靜態(tài)方法Thread.Sleep(int ms)可以讓當前線程(它自動調用Thread.CurrentThread)暫停指定毫秒的時間。
      如果使用Thread.Sleep(0)那么當前線程將一直處于等待中,直到另一個線程調用這個線程的實例方法Thread.Interrupt方法,
      等待才會結束。
      使用Thread.Suspend方法也能掛起線程,Thread.Suspend方法可以被當前線程或其他線程調用,而Thread.Sleep(0)
      只能由當前線程在執(zhí)行體中調用。當線程用Thread.Suspend掛起時,必須用Thread.Resume方法恢復。不論Thread.Suspend
      方法調用了多少次,只要調用Thread.Resume方法一次就可以線程恢復執(zhí)行。用Thread.Suspend方法并不會阻塞線程,
      調用立即返回。而Thread.Sleep(0)則會阻塞線程。所以確切地說Thread.Sleep(0)暫停線程,而不是掛起線程。
      使用Thread.Abort方法可以終止正在執(zhí)行的線程。當Thread.Abort方法被調用時,線程不會立即終止執(zhí)行。運行環(huán)境將會
      等待,直到線程到達文檔中所描述的“安全點”。如果要確保線程已經完全停止,可以使用Thread.Join方法。這是一個同步
      調用,同步調用意味著直到線程完全停止,調用才會返回。
      Thread.Priority屬性用于設置的線程的優(yōu)先級。其值是Thread.ThreadPriority枚舉值,可以設為Highest, AboveNormal,
      Normal, BelowNormal, Lowest。缺省值是Thread.ThreadPriority.Normal。
      線程的同步是為了解決多個線程同時使用同一對象產生的一些問題。通過同步,可以指定代碼的臨界區(qū)(critical section),
      一次只有一個線程可以進入臨界區(qū)。
      使用System.Monitor類(鎖定與信號量)進行線程同步:
      using System;
      using System.Threading;

      public void SaveData(string text) //線程執(zhí)行函數(shù)或線程執(zhí)行函數(shù)調用的對象的方法
      {
        ...   //執(zhí)行其他一些不需要同步的處理

        Monitor.Enter(this); //獲取對象的Monitor鎖
        ...   //執(zhí)行需要同步的處理
        Monitor.Exit(this); //釋放對象的Monitor鎖

        ...   //執(zhí)行其他一些不需要同步的處理
      }
      說明:當執(zhí)行Monitor.Enter方法時。這個方法會試圖獲取對象上的Monitor鎖,如果另一個線程已經擁有了
      這個鎖,這個方法將會阻塞(block),直到這個鎖被釋放。
      也可用C#的lock語句來獲得和釋放一個Monitor鎖。上面同步寫成:
      public void SaveData(string text) //線程執(zhí)行函數(shù)或線程執(zhí)行函數(shù)調用的對象的方法
      {
        ...   //執(zhí)行其他一些不需要同步的處理

        lock(this)  //獲取對象的Monitor鎖,代碼塊執(zhí)行完成后釋放Monitor鎖
        {
        ...   //執(zhí)行需要同步的處理
        }

        ...   //執(zhí)行其他一些不需要同步的處理
      }

      也可以使用System.Threading名稱空間的Mutex類(互斥類)進行線程同步。與Monitor鎖一樣,一次只有一個線程
      能獲得一個給定的互斥。但Mutex要慢得多,但它增加了靈活性。例:
      using System;
      using System.Threading;
      class Database
      {
        Mutex mutex = new Mutex(false); //創(chuàng)建一個互斥,但不立即獲得它
           //注意:創(chuàng)建互斥在需要同步的方法之外,實際上它只要創(chuàng)建一個實例
        public void SaveData(string text) //需要同步的方法
        {
          mutex.WaitOne();  //等待獲得互斥
          ...    //需要同步的處理
          mntex.Close();  //釋放互斥
        }
      }

      Mutex類重載了三個構造函數(shù):
      Mutex()       //創(chuàng)建并使創(chuàng)建類立即獲得互斥
      Mutex(bool initiallyOwned)    //創(chuàng)建時可指定是否要立即獲得互斥
      Mutex(bool initiallyOwned, string muterName)  //還可以指定互斥的名稱
      Mutex.WaitOne方法也重載了三次:
      Mutex.WaitOne()      //一直等待
      Mutex.WaitOne(TimeSpan time, bool exitContext)  //等待TimeSpan指定的時間
      Mutex.WaitOne(int milliseconds, bool exitContext) //等待指定的毫秒
      線程的用法:
      1)并發(fā)操作:比如一個程序監(jiān)視多個COM口,當每個COM接到信息時執(zhí)行一段處理時。
      2)復雜長時間操作:一個長時間的復雜操作可能會使界面停滯,停止用戶響應,如果還允許用戶停止它,
      或者顯示進度條、顯示操作執(zhí)行進程信息時。
      反射(Reflection)就是能夠在運行時查找類型信息,這是因為.NET編譯的可執(zhí)行(PE)文件中包括MSIL和元數(shù)據(jù)(metadata)。
      反射的中心是類System.Type。System.Type是一個抽象類,代表公用類型系統(tǒng)(Common Type System, CTS)中的一種類型。
      using System;
      using System.Reflection; //反射命名空間,必須引用

      public static void Main(string[] args)
      {
        int i = 6;
        Type t = i.GetType();   //根據(jù)實例得到類型
        t = Type.GetType("System.Int32"); //根據(jù)類型的字符名稱得到類型
      }

      通過Assembly類可以得到已經編譯.NET Framework程序的中所有類型,例:
      using System;
      using System.Diagnostics;  //為了使用Process類
      using System.Reflection;  //為了使用Assembly類

      class GetTypesApp
      {
        protected static string GetAssemblyName(string[] args)
        {
          string assemblyName;
          if (0 == args.Length) //如果參數(shù)為空,取當前進程的名稱
          {
            Process p = Process.GetCurrentProcess();
            assemblyName = p.ProcessName + ".exe";
          }
          else
            assemblyName = args[0]; //取第一個參數(shù),即當前運行程序名

          return assemblyName;
        }

        public static void Main(string[] args)
        {
          string assemblyName = GetAssemblyName(args);
          Assembly a = Assembly.LoadFrom(assemblyName); //調用編譯程序集
          Type[] types = a.GetTypes();   //得到多個類型
          foreach (Type t in types)    //遍歷類型數(shù)組
          {
          ...  //取得t.FullName,t.BaseType.FullName等類型信息
          }
        }
      }
      一個應用程序可以包括多個代碼模塊。若要將一個cs文件編譯一個模塊,只要執(zhí)行下面的命令:
      csc /target:module 要編譯的模塊.cs  //csc是C Sharp Compiler(C#編譯器)
      然后在應用程序中using編譯的模塊.cs中的NameSpace即可應用了。
      要反射應用程序中所有代碼模塊(Module),只要:
      Assembly a = Assembly.LoadFrom(assemblyName); //應用程序的物理文件名
      Module[] modules = a.GetModules();
      foreach(Module m in modules)
      {
      ... //顯示m.Name等
      }
      后期綁定(latebinding),例:
      string[] fileNames = Directory.GetFiles(Environment.CurrentDirectory, "*.dll");
      foreach (string fileName in fileNames)
      {
        Assembly a = Assembly.LoadFrom(fileName);
        Type[] types = a.GetTypes();
        foreach(Type t in types)
        {
          if (t.IsSubclassOf(typeof(CommProtocol)))  //判斷是否有CommProtocol的派生類
          {
            object o = Activator.CreateInstance(t);  //生成實例
            MethodInfo mi = t.GetMethod("DisplayName");
            mi.Invoke(o, null);    //調用方法
          }
        }
      }
      //帶參數(shù)的例子
      namespace Programming_CSharp
      {
        using System;
        using System.Reflection;
       
        public class Tester
        {
          public static void Main( )
          {
            Type t = Type.GetType("System.Math");
            Object o = Activator.CreateInstance(t);

            // 定義參數(shù)類型
            Type[] paramTypes = new Type[1];
            paramTypes[0]= Type.GetType("System.Double");

            MethodInfo CosineInfo = t.GetMethod("Cos", paramTypes);

            //設置參數(shù)數(shù)據(jù)
            Object[] parameters = new Object[1];
            parameters[0] = 45;

            //執(zhí)行方法
            Object returnVal = CosineInfo.Invoke(o, parameters);
            Console.WriteLine("The cosine of a 45 degree angle {0}", returnVal);
          }
        }
      }
      動態(tài)生成代碼和動態(tài)調用的完整例子:
      //動態(tài)生成代碼的部分
      using System;
      using System.Reflection;
      using System.Reflection.Emit;  //動態(tài)生成代碼必須引用

      namespace ILGenServer
      {
        public class CodeGenerator
        {
          public CodeGenerator()
          {
            currentDomain = AppDomain.CurrentDomain;  //得到當前域
            assemblyName = new AssemblyName();  //從域創(chuàng)建一個程序集
            assemblyName.Name = "TempAssembly";
            //得到一個動態(tài)編譯生成器,AssemblyBuilerAccess.Run表示只在內存中運行,不能保存
            assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilerAccess.Run);
            //從編譯生成器得到一個模塊生成器
            moduleBuilder = assemblyBuilder.DefineDynamicModule("TempModule");
            //模塊生成器得到類生成器
            typeBuilder = moduleBuilder.DefineType("TempClass", TypeAttributes.Public);
            //為類添加一個方法
            methodBuilder = typeBuilder.DefineMethod("HelloWord", MethodAttributes.Public, null, null);
            //為方法寫入代碼,生成代碼必須使用到IL生成器
            msil = methodBuilder.GetILGenerator();
            msil.EmitWriteLine("Hello World");
            msil.Emit(OpCodes.Ret);
            //最后還需要編譯(build)一下類
            t = typeBuilder.CreateType();
          }
          AppDomain currentDomain;
          AssemblyName assemblyName;
          AssemblyBuilder assemblyBuilder;
          ModuleBuilder moduleBuilder;
          TypeBuilder typeBuilder;
          MethodBuilder methodBuilder;
          ILGenerator msil;
          object o;
          Type t;
          public Type T
          {
            get
            {
              return this.t;
            }
          }
        }
      }
      //動態(tài)調用的部分
      using System;
      using System.Reflection;
      using ILGenServer;  //引用動態(tài)生成代碼的類
      public class ILGenClientApp
      {
        public static void Main(
        {
          CodeGenerator gen = new CodeGenerator(); //創(chuàng)建動態(tài)生成類
          Type t = gen.T;
          if (null != t)
          {
            object o = Activator.CreateInstance(t);
            MethodInfo helloWorld = t.GetMethod("HelloWorld"); //為調用方法創(chuàng)建一個MethodInfo
            if (null != helloWorld)
            {
              helloWorld.Invoke(o, null);  //調用方法
            }
          }
        }
      }
      調用DLL
      using System;
      using System.Runtime.InteropServices; //為了使用DLLImport特性

      class PInvokeApp
      {
        [DllImport("user32.dll", CharSet=CharSet.Ansi)] //CharSet.Ansi指定Ansi版本的函數(shù)(MessageBoxA),CharSet.Unicode指定Unicode版本的函數(shù)(MessageBoxW)
        static extern int MessageBox(int hWnd, string msg, string caption, int type);  //聲明DLL中的函數(shù)
       
        //[DllImport("user32.dll", EntryPoint="MessageBoxA")] //用這種方法使用不同的函數(shù)名
        //static extern int MsgBox(int hWnd, string msg, string caption, int type);
       
        //[DllImport("user32.dll", CharSet=CharSet.Unicode)]  //調用Unicode版的DLL函數(shù)
        //static extern int MessageBox(int hWnd, [MarshalAs(UnmanagedType.LPWStr)]string msg,
        // [MarshalAs(UnmanagedType.LPWStr)]string caption, int type); //將LPWStr翻譯為string型,缺省情況系統(tǒng)只將LPStr翻譯成string
        public static void Main()
        {
          MessageBox(0, "Hello, World!", "CaptionString", 0);  //調用DLL中的函數(shù)
        }
      }
      例2,使用回調:
      class CallbackApp
      {
        [DllImport("user32.dll")]
        static extern int GetWindowText(int hWnd, StringBuilder text, int count);

        delegate bool CallbackDef(int hWnd, int lParam);

        [DllImport("user32.dll")]
        static extern int EnumWindows(CallbackDef callback, int lParam);

        static bool PrintWindow(int hWnd, int lParam)
        {
          StringBuilder text = new StringBuilder(255);
          GetWindowText(hWnd, text, 255);
          Console.WriteLine("Window Caption: {0}", text);
          return true;
        }

        static void Main()
        {
          CallbackDef callback = new CallbackDef(PrintWindow);
          EnumWindows(callback, 0);
        }
      }
      關鍵字unsafe指定標記塊在非控環(huán)境中運行。該關鍵字可以用于所有的方法,包括構造函數(shù)和屬性,
      甚至還有方法中的代碼塊。關鍵字fixed負責受控對象的固定(pinning)。Pinning是一種動作,向
      垃圾收集器(Garbage Collector, GC)指定一些不能被移動的對象。為了不在內存中產生碎片,.NET
      運行環(huán)境把對象四處移動,以便于最有效地利用內存。使用fixed后指定對象將不會被移動,所以就
      可以用指針來訪問它。
      C#中只能得到值類型、數(shù)組和字符串的指針。在數(shù)組的情況下,第一個元素必須是值類型,因為C#
      實際上是返回一個指向數(shù)組第一個元素的指針,而不是返回數(shù)組自身。
      & 取一個變量的內存地址(即指向該變量的指針)
      * 取指針所指變量的值
      -> 取成員
      例:
      using System;
      class UnsafeApp
      {
        public static unsafe void GetValues(int* x, int* y)
        {
          *x = 6;
          *y = 42;
        }

        public static unsafe void Main()
        {
          int a = 1;
          int b = 2;
          GetValues(&a, &b);
        }
      }
      fixed語法為:fixed(type* ptr = expression) statements
      其中type也可以為非控類型,也可是void;expression是任何產生一個type指針的表達式;
      statements是應用的代碼塊。例:
      fixed (int* f = &foo.x)  //foo是Foo類的一個實例,x是Foo類的一個int屬性
      {
        SetFooValue(f);  //SetFooValue方法的定義為unsafe static void SetFooValue(int* x)
      }
      傳統(tǒng)的COM組件可以通過互操作層(COM Interop)與.NET運行環(huán)境交互?;ゲ僮鲗犹幚碓谕泄苓\行環(huán)境和非托管區(qū)域
      中的COM組件操作之間傳遞所有的消息。
      要使COM組件能在.NET環(huán)境中使用,必須為COM組件生成元數(shù)據(jù)。.NET運行環(huán)境用元數(shù)據(jù)層業(yè)判斷類型信息。在運行時刻
      使用類型信息,以便生成RCW(Runtime Callable Wrapper,運行時可調用包裝)。當.NET應用程序與COM對象交互時,
      RCW處理對COM對象的裝載和調用。RCW還完成許多其他的工作,如管理對象標識、對象生存周期以及接口緩沖區(qū)。
      對象生存周期管理十分關鍵,因為.NET GC把對象到處移動,并且當對象不再使用時,自動處理這些對象。RCW服務告訴
      .NET,應用程序正與托管.NET組件交互,同時又使非托管COM組件“覺得”COM對象是被傳統(tǒng)的COM客戶端調用的。
      為了為COM組件生成元數(shù)據(jù)包裝,必須使用tlbimp.exe(TypeLib Importer)工具:
      tlbimp some_COM.tlb /out:som_COM.dll

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多