類型基礎

来源:http://www.cnblogs.com/liunlls/archive/2016/09/22/5892310.html
-Advertisement-
Play Games

所有類型都繼承自System.Object System.Object的基本方法 | 名稱 | 訪問級別|說明 | | | | | |Equals()|public|如果兩個對象有相同的值就返回true| |GetHashCode()|public|返回對象的值的哈希碼 |ToString()|pu ...


所有類型都繼承自System.Object

System.Object的基本方法

名稱 訪問級別 說明
Equals() public 如果兩個對象有相同的值就返回true
GetHashCode() public 返回對象的值的哈希碼
ToString() public 預設返回類型的完整名稱(this.GetType().GetFullName)
GetType() public 指出調用GetType()方法的對象的類型
MemberwiseClone() protected 可以創建類型的一個新的實例,並將新對象的實例欄位與this設置一致,返回的是新實例的引用

new操作符

CLR要求所有對象都是通過new來創建的,如下

 Book book = new Book("語文");

new操作符創建對象的過程:
1.計算類型及其所有基類類型(直到Object)中定義的所有實例欄位需要的位元組數;堆上的對象成員還需要計算“類型對象指針”和“同步塊索引”的字計數,這些成員由CLR管理。
2.從托管堆中分配類型要求的位元組數,分配的所有位元組都設置為0。
3.初始化對象的“類型對象指針”和“同步快索引”。
4.對用類型的實例構造器,向其傳入在對new的調用中指定的任何參數(上面代碼中傳入的“語文”);編譯器會在構造函數中生成代碼對基類構造器進行調用,每個類型的構造器在調用時,都負責初始化由這個類型定義的實例欄位;由於Object類型沒有實例欄位,該構造器只是簡單的返回,並沒有任何操作。
執行完new操作後,會返回一個新建的對象引用(或指針),如上面的代碼將這個引用保存到了變數book中。

類型轉換

CLR的一個重要特性就是類型安全,在運行時,總是知道一個對象是什麼類型。
CLR允許將一個對象轉換為它的派生類型和基類型;向基類型轉換時是安全的隱士轉換,向派生類轉換時有可能在運行時會失敗,所以只能進行顯示轉換。

 //Object是Teller的基類,直接隱式轉換
 object o = new Teller();
 //需要強制轉換
 Teller teller = (Teller)o;

使用is和as操作符來轉型

is檢查對象是否相容於制定類型,返回一個布爾值;is操作符永遠不會拋出異常,即使對象引用的是null。

  if (obj is Teller)
  {
      Teller teller = (Teller)obj;
  }

上面的代碼是is的常用操作方式,CLR會對對象進行兩次類型檢查,雖然這樣增強了類型的安全性檢查,但無疑浪費了性能;為了避免這個問題,可以通過as的方式進行轉型。

  Teller teller = obj as Teller;
  if (teller != null)
  {
  }

CLR會檢測obj是否相容於Teller,如果是,as返回一個非null的引用,如果不相容,as操作符將返回null

命名空間和程式集

命名空間用於對相關類型進行邏輯性的分組,如System.Text定義了一組字元串處理的類型

System.Text.StringBuilder builder = new System.Text.StringBuilder();

顯然,這樣寫代碼非常繁瑣;C#編譯器通過使用using減少了輸入量。

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

namespace TypeBasis
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder s = new StringBuilder();
        }
    }
}

對於編譯器來說,命名空間的作用就是使類型更具有唯一性。當兩個類型名稱發生衝突,為了消除歧義,必須顯示的告訴編譯器使用的是哪一個類型。使用using還可以創建類型或者命名空間的別名。

using System;
using ST = System.Text;

namespace TypeBasis
{
    class Program
    {
        static void Main(string[] args)
        {
            ST.StringBuilder builder = new ST.StringBuilder();
        }
    }
}

CLR不知道命名空間的任何類型,訪問一個類型時,CLR需要知道類型的完整名稱。
當兩個類型的命名空間及類型名稱都一樣的時候,可以通過外部別名消除歧義;為了避免發生這種問題,應該常使用公司名稱(而不是公司名稱首字母縮寫或者其他簡寫)來作為自己的頂級命名空間名稱。
namespace指令的作用是告訴編譯器為源代碼中出現的每個類型名稱附加命名空間名稱首碼,減少程式員的輸入量。
命名空間和程式集之間不一定是相關的,同一個命名空間也有可能在不同的程式集中。

運行時的相互聯繫

通過下麵的代碼來瞭解運行時間的相互關係

    class Program
    {
        static void Main(string[] args)
        {
            //當程式運行時,並即將調用到上面的`Main`中的`DoSomething()`方法時,首先JIT(即時編譯器)將`DoSomething()`的IL(中間代碼)轉換成CPU指令,
            //並確保方法中的定義了的類型的程式集都已經載入,利用程式集的元數據,CLR創建一些結構數據來表示類型本身;在每個對象中,最後都會包含一個方法表,類型中定義的每個方法都有一個對應的記錄
            //當`DoSomething()`方法開始執行時,會自動為方法中的局部變數初始化值(`null`或者0),如果未顯示為局部不變數初始化,調用的時候將引發“使用了未賦值的局部變數”異常    
            DoSomething();
        }

        static void DoSomething()
        {
            Employee e;
            int year;
            //創建Manager類型的一個實例,並分配實例所需要的記憶體(實例欄位及所有基類的實例欄位所需的位元組數),並將實例欄位設置為null或者0
            //然後再調用構造函數(構造函數的本質是修改實例欄位的一個方法)
            //new操作符將Manager對象的記憶體地址返回,並保存在變數e中
            e = new Manager();
            //調用靜態方法時,CLR會定位定義靜態方法的類型對應的類型對象,然後JIT在類型對象中查找與被調用的方法相關的記錄,對方法JIT編譯,再調用JIT編譯的代碼
            //e不再引用上面的Manager對象,它將被GC回收,GC回收後將釋放它所占用的記憶體,e將保存由Employee.Lookup("Joe")返回來的一個新的地址
            e = Employee.Lookup("Joe");
            //調用Employee類型實例的GetYearEmployed方法,如果Employee中沒有定義GetYearEmployed方法,JIT編譯器會沿著Employee的基類查找,知道Object
            year = e.GetYearEmployed();
            //如果Employee.Lookup("Joe")返回的是一個Manager引用,將調用Manager類型中的GenProgressReport重寫方法,如果返回的是Employee類型引用,調用的就是Employee中的虛方法
            e.GenProgressReport();
        }
    }

    public class Employee
    {
        public int GetYearEmployed()
        {
            //TODO: do something...
            return default(int);
        }
        public virtual string GenProgressReport()
        {
            //TODO: do something...
            return default(string);
        }
        //靜態成員所需的位元組包含在對象本身
        public static Employee Lookup(string name)
        {
            //TODO: do something...
            return default(Employee);
        }
    }

    public class Manager : Employee
    {
        public override string GenProgressReport()
        {
            //TODO: do something...
            return default(string);
        }
    }

CLR創建類型對象時,必須初始化“類型對象指針”成員;CLR開始在一個進程中運行時,會立即為MSCorLib.dll定義的System.Type類型創建一個特殊的類型對象。ManagerEmployee都是該對象的“實例”,因此,它們的對象指針成員會初始化為對System.Type的類型對象的引用;當然System.Type的“類型對象指針”成員指向的是它本身。
System.ObjectGetType()方法返回的是存儲在制定對象的“類型對象指針”成員中的地址,即指向對象的類型對象的一個指針,這樣就可以知道系統中任何對象的類型。

參考:《CLR via C#》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先來講講TcpTrace實現的基本原理。說簡單點,TcpTracer就是一個監聽/轉發器(Listening/Forwarding),就是一個路由器。當啟動的時候,我們需要設置兩個埠:監聽埠(Listening Port)和目的主機(Destination Server)與目的埠(Desti... ...
  • 最近比較忙,好久沒寫博客了。個人感覺最好的進步就是寫東西。哈哈。 一般我們使用ADO.net從資料庫中讀取數據返回的集合是DataSet類型的。有時候我們需要進行轉換成List<T>集合。一般的做法是在DAL層中,寫個方法進行轉換。(每個表寫一個)。累哦!~ 所以我就想,能不能寫個工廠,傳入Data ...
  • 菜單和工具欄: 1. MenuStrip --頂部菜單分割線1. “-”號 ,2. 右鍵 插入 split 快捷鍵:每一個項右鍵屬性的最下麵可以設置快捷鍵不管選項隱藏還是菜單隱藏,快捷鍵都管用 2、ContextMenuStrip:右鍵菜單 每個控制項都可以有右鍵菜單 3、StatusStript:底 ...
  • Calendar 日曆; FileUpdate 文件上傳; Image 圖片,可以直接給URL; Repeater: HeaderTemplate - 在載入開始執行一遍 ItemTemplate - 有多少條數據,執行多少遍 FooterTemplate - 在載入最後執行一遍 Alternati ...
  • Repeater: HeaderTemplate - 在載入開始執行一遍 ItemTemplate - 有多少條數據,執行多少遍 FooterTemplate - 在載入最後執行一遍 AlternatingItemTemplate - 交替項模板 把性別0、1改成男女: 把民族顯示名稱替換代號: 調 ...
  • ...
  • web項目製作成安裝包是為了方便發佈到伺服器上,本文主要講了安裝包製作,IIS部署,資料庫安裝,卸載時刪除IIS網站和資料庫 博文參考鏈接:http://www.cnblogs.com/huxj/archive/2010/09/10/1823637.html 下麵是本人通過網上資料和自己的思考總結進 ...
  • 1:頁面前端中對單個值進行轉碼 url: "ExtjsDemo.aspx?userName=" + encodeURI(userName) + "&passWord=" + encodeURI(pwd) + "" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...