C#語法最基礎知識


一. System.Object

 

公共實例方法

簡要說明

virtual bool Equals(object obj)   確定兩個對象是否相等,如果相等則返回true,否則false
virtual int GetHashCode()   返回this對象的一個哈希碼,如果該對象被一個集合當作鍵值使用,則這個值將起作用
Type GetType()   返回當前對象的類型。類型由一個繼承自 System.Type的實例對象表示
virtual string ToString()   返回一個可以代表當前對象的字符串,在 System.Object中該方法返回當前對象類型的完整名稱

      實例 Equals 方法

              比較當前對象和參數對象是否相等。

              在 System.Object中,這個方法是“引用比較”比較this引用和參數引用是否引用同一個對象,是則true否則false

              假設兩個字符串變量a,b分別賦相同值,邏輯相同但此時按照Equals()規則則不同。故設計新類時可重寫此方法

        實現內容相同。.NET中,System.ValueType作為所有值類型的基類,重寫此方法以實現內容的比較。

     實例 GetHashCode 方法

            用來返回當前對象的一個哈希碼,當對象被用作集合的鍵值時,此方法被調用。

             3種方法檢驗GetHashCode的算法正確性

                1. 如果兩個對象相等(Equals),則兩個對象調用GetHashCode方法應該返回相同值

                2. 同一個對象無論在何種 場合調用GetHashCode方法,返回值應該返回想同值

                3. 不同對象調用GetHashCode方法,返回值應該均勻分布在整數集合之中

    GetType 方法

              公共方法:GetType。 返回一個代表當前“對象類型”的實例。

              即查找程序集中的元數據,找到該類型的定義。 System.Object的ToString方法利用了 GetType方法

公共靜態方法

簡要說明

bool Equals(object objA, object objB)   確定兩個對象是否相等,如果相等則返回true,否則false
bool ReferenceEquals(object objA, object objB)   比較兩個對象的引用是否相等。相等則返回true,否則false

      ReferenceEquals方法

                實現兩個對象的引用比較,如果引用相等返回true,否則false。無論是何種值類型,返回結果必為false。

      Equals方法

                 實現較簡單,依靠實例的Equals方法實現內容比較

 

public static bool Equals(object left, object right)
      {
          //查看是否是同一對象
          if (left == right)
              return true;
          if ((left == null) || (right == null))
              return false;
          return left.Equals(right);
      }

受保護實例方法

簡要說明

object MemberwiseClone()   淺復制當前對象實例,並返回復制對象的引用
Finalize   .NET的析構方法

 

二. 值類型與引用類型

(1)值類型

       繼承自 System.ValueType 

       常有的值類型包括 結構、枚舉、整數型、浮點數、布爾型等

(2)引用類型

       以class關鍵字定義的類型都是引用類型

(3)區別

     1).賦值時區別

           值類型的變量將直接獲得一個真實的數據副本

           引用類型的賦值僅僅是吧對象的引用賦給變量,可導致多個變量引用一個實際對象實例上

     2).內存分配的區別

           值類型的對象會在堆棧上分配內存,

           引用類型的對象會在上分配內存。

    3).繼承結構的區別

           值類型都繼承自 System.ValueType 對象分配在 堆棧 上

           System.Object和所有引用類型對象分配在 堆 上

 

三.裝箱和拆箱

     裝箱

            System.Object是所有值類型的基類,所有值類型必然可以隱式轉換成 System.Object類型。轉換發生時,CLR需要做額外的工作把堆棧上的值類型移到堆上。 這個操作為 裝箱。

   

            步驟

                1. 在堆上分配一個內存空間,大小等於需要裝箱的值類型對象大小加上兩個引用類型對象都擁有的成員:類型對象

            指針和同步塊引用

                2. 把堆棧上的值類型對象復制到堆上新分配的對象

                3. 返回一個指向堆上新對象的引用,並且存儲到堆棧上被裝箱的那個值類型的對象里

這些步驟不需程序員自己編寫,在出現裝箱的地方,編譯器會自動加上執行以上功能的中間代碼。

image

     拆箱

            裝箱的反操作,把堆中的對象復制到堆棧中,並且返回其值

            過程中,拆箱操作將 判斷拆箱的對象類型 和 將要被復制的值類型引用 是否一致,不一致將拋出一個    InvalidCastException的異常

     

     影響: 裝箱與拆箱意味着堆和堆棧空間的一系列操作,這些操作對性能代價很大,尤其是在速度相對於堆棧慢很多的堆操作,並且這些操作可能引發垃圾回收。

    

      適用場合:

            1. 值類型格式化輸出 (裝箱)

        以下代碼可編譯執行,但會引發一次不必要的裝箱操作

       int i = 10;
      Console.WriteLine("i的值是:"+i);

      優化后,不在涉及裝箱

       int i = 10;
       //ToString方法得到一個字符串對象,字符串是引用類型
       Console.WriteLine("i的值是:o{0}"+i.ToString());

 

           2.System.Object類型的容器

        常用的容器類如 ArrayList就是System.Object容器,任何值類型被放入ArrayList的對象中,都會引發一次裝箱操作,相應的取出引發一次拆箱操作。

         因此,在可以確定類型的情況下應該使用泛型技術而避免使用System.Object類型容器。

 

三. C#中是否全局變量

      C#中沒有傳統意義的全局變量,在C#程序中,任何對象數據都必須屬於某個類型。

      通過公共靜態變量,可以實現以前全局變量的所有功能。如asp.net程序中使用Application對象和使用配置文件存儲可配置數據等。

 

四. 結構  struct

            可看作 一個微型的類。 支持 私有成員變量和公共成員變量

                                              支持屬性和方法

                                              支持構造函數 但 不能自定義無參的構造方法,C#編譯器會為結構添加一個無參公共構造

                                        函數 在該方法中成員被自動化為0。也不能在定義時設置初始值

                                              支持重寫定義在System.Object中的虛方法

                                           不支持繼承

             繼承自 System.ValueType 類,故struct是值類型。

             經常用於存儲數據的集合,但那些涉及復雜操作的類型,應被設計成類而不是結構。

 

五. 類型初始化器

    1.概念

           在.NET中,每個類型都有一個初始化器。可以自己定義初始化器,也可以使用默認的編譯器添加的初始化器

           類型的初始化器擁有和類型相同的名字 以 static 關鍵字定義,並且沒有參數,也沒有任何返回值。

           類型初始化器不同於構造函數,初始化器不能被顯式地調用,並且每個類型只能有一個類型初始化器。 CLR保證

    的任何靜態成員被使用之前,類型的初始化器會被調用。這個概念和靜態成員變量的初始化表達式本質上沒區別。

public class CCtor
       {
           //初始化表達式
           public static int m_Int = 1;
           //初始化器
           static CCtor()
           {
               m_Int = 2;
           }
           //構造函數
           public CCtor()
           {
               Console.WriteLine("構造函數調用。");
           }
           static void Main(string[] args)
           {
               Console.Read();
           }

       }

C# 編譯器在編譯時,會把所有靜態成員變量初始化表達式加入到初始化器中,並且添加的位置在自定義的初始化器內容之前。

 

    2.調用策略

       在中間代碼中初始化器的名字為cctor()。 兩種調用策略

         1). 在類型不具有BeforeFieldInit元數據屬性時,CLR將在類型的任何成員被使用之前調用初始化器。

         2). 在當類型具有BeforeFieldInit元數據屬性時,CLR可以自由調度初始化器的調用,只需確保任何靜態成員變量在使用之前初始化器已經被調用。

 

六. 方法參數的的傳遞方式

 

關鍵字

簡要說明

Ref   引用傳遞參數,需要在傳遞前初始化
Out   引用傳遞參數,需要在返回前初始化
Params   可以指定在參數數目可變處采用參數的方法參數

1). ref和out關鍵字

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class useles
    {
        static void Main(string[] args)
        {
            int i = 0;
            Console.WriteLine("原始值:" + i.ToString());
            NotRef(i);
            Console.WriteLine("調用非引用傳遞參數方法后:" + i.ToString());
            Ref(i);
            Console.WriteLine("調用引用傳遞參數方法后:"+i.ToString()J);
            Console.Read();
        }
        //不使用ref關鍵字來傳遞參數
        public static void NotRef(int i)
        {
            i++;
        }
        //使用ref關鍵字來傳遞參數
        public static void Ref(int i)
        {
            i++;
        }
    }
}

結果為  0,0,1 

NotRef方法並不以引用方式傳遞參數,所以方法得到的是整數i的一個副本,怎么操作,與原數據無關。

 

2). params

      params是一個非常實用的關鍵字,它允許方法在定義時不確定參數的數量,類似於數組參數。

      缺點: 方法聲明了params參數后,不允許在其后面再有任何參數。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class useles
    {
        //不使用params關鍵字來傳遞參數
        public static void NotParams(Object[] par)
        {
            foreach (Object obj in par)
                Console.WriteLine(obj);
        }
        //使用params關鍵字來傳遞參數
        public static void ParamsParam(params Object[] par)
        {
            foreach (Object obj in par)
                Console.WriteLine(obj);
        }
        //測試
        static void Main(string[] args)
        {
            String s = "我是字符串";
            int i = 10;
            double f = 2.3;
            //需現聲明數組對象以通過其傳入
            Object[] par = new Object[3] { s, i, f };
            NotParams(par);

            //params關鍵字方式
            ParamsParam(s, i, f);
            Console.Read();
            
        }
      
    }
}

 

七. 訪問級別

類型訪問級別

名稱

C#中關鍵字

簡述

Private private   同一類型的所有方法或類型中的內嵌類型的所有方法可訪問
Family protected   同一類型的所有方法、類型中的內嵌類型的所有方法和派生類型中的所有方法可訪問
Assemly internal   同一程序集中的所有方法可訪問
Family&Assemly 沒有實現   同時滿足Family約束和Assemly約束的所有方法
Assemly or Family protected internal   所有滿足Assembly約束或滿足Family約束的方法
Public public   所有方法都可訪問

 

類型成員的訪問級別

類型

C#中默認的可訪問性級別

可設置的可訪問性級別

Enum public   不可設置
Class private   pubic
  protected
  internal
  private
  protected internal
Interface public   不可設置
Struct private   public
  internal
  private

 

八. 深復制與淺復制

     淺復制 

            復制一個對象時,復制原始對象中所有的非靜態值類型成員和所有的引用類型成員引用

     深復制

            不因復制所有的非靜態值類型成員,而且復制所有引用類型成員實際對象

image

基類System.Object已經為所有類型都實現了淺復制 object MemberwiseClone() 方法。

接口 ICloneable 只包含了一個方法 Clone()。繼承此接口的類根據取舍不同實現Clone()可實現為深復制或前復制。

也可以用其他方式實現深復制,不局限與IConeable接口的Clone()方法。

可被繼承的類應避免實現IConeable接口,因為那樣將導致所有子類都必須實現ICloneable接口。

 

九. 循環

    while 和 do…while經常用在循環不確定的場合,死循環危險系數較高。

    for 和 foreach 經常用來遍歷數組和集合。for循環功能強大

    foreach用來遍歷那些實現了IEnumberable的容器類型。數組和常用容器類如ArrayList、List等都實現了IEnumberable接口。 但它有一定限制

      不能改變項目值,不能對項目賦值,不能通過屬性為項目內部成員賦值。 但項目的公共方法可以被調用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class useles
    {
        public struct A
        {
            public int _i;
            //通過屬性改變成員
            public int I
            {
                set { _i = value; }
            }
            //通過公共方法改變成員
            public void ModifyI(int i)
            {
                _i=i;
            }
            public override string ToString()
            {
                return _i.ToString();
            }
        }

        //測試
        static void Main(string[] args)
        {
            A[] array = new A[3];
            foreach (A a in array)
            {
                //a=new A(1);  //編譯不通過,不能改變項目
                //a._i=1;         //編譯不通過,不能改變項目成員變量
                //a.I=1;          //編譯不通過,不能通過屬性改變成員變量
                a.ModifyI(1);   
                Console.WriteLine(a);
            }
 
            
        }
      
    }
}

十. using機制

    1)概述

     .NET的環境中,托管的資源由.NET的垃圾回收機制來釋放

                         非托管的資源需要程序員自己手動地釋放。

      兩種主動和被動釋放非托管資源方式。

                   IDisposable接口的Dispose方法

                   類型自己的Finalize方法

    任何帶有非托管資源的類型,都有必要實現IDisposable的Dispose方法,並且在使用完這些類型之后需要手動地調用對象的Dispose方法來釋放對象中的非托管資源。

    如果類型正確地實現了Finalize方法,即使Dispose方法不被調用,非托管資源也最終會被釋放,但那時資源已被很長時間無謂地占用了

     2)using語句提供了一個高效的調用對象Dispose方法的方式。

          對於任何實現IDisposable接口的類型,都可使用using語句,而對於那些沒有實現IDisposable接口的類型,使用using則導致編譯錯誤

          using 語句能夠保證使用的對象的Dispose方法在using語句塊結束時被調用,無論是否有異常被拋出。

          C#編譯器在編譯時為using語句加上try/finally語句塊。本質與異常捕捉語句一樣,但是它更簡潔。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM