程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> CLR筆記:6.類型和成員基礎

CLR筆記:6.類型和成員基礎

編輯:關於.NET

1.Class的可見性有public和internal兩種,public對所有程序集都可見,internal僅對其所在的程序 集可見。默認是public的。

2.友元程序集,

使用friend assembly可以實現單元測試,而不使用反射技術。

書上講的是按照命令行編譯。

我測試用的是vs2005的solution,如下:

3.成員的可訪問性

成員默認是private的,接口類型的成員都是public的。

子類重寫父類的成員時,原始成員與重寫成員要有相同的可訪問性——C#的約束;CLR的約束是,重寫 成員的可訪問性不能更低。

CLR和C#是不一樣的,如表:

CLR術語 C#術語 Private private Family protected Family and Assembly 不支持 Assembly internal Family or Assembly protected internal Public public

4.靜態類

static只能用於class,不能用於struct,因為CLR要求值必須實例化,而且不能控制實例化過程。

C#對靜態類的約束:

靜態類必須直接從System.Object派生

靜態類不能實現任何接口

靜態類只能定義靜態成員:字段,方法,屬性,事件

靜態類不能用作:字段,方法,參數,局部變量。

在MSIL中,不會為靜態類生成ctor,會將其標記為abstract和sealed

5.部分類

CLR不支持partial,只是C#的語法。所以某個類型的源碼必須使用同一種編程語言

6.組件,多態和版本控制

.NET版本號2.7.1.34,包含4個部分:主版本號,次版本號,內部版本號,修訂版本號。

修訂版本,向後兼容,改變內部/修訂版本號;

發布新版本,不向後兼容,改變主/次版本號。

多態中,子類重寫父類的虛方法,會引起版本控制問題,即父類發生改變,其版本低於子類版本,會 導致子類行為變化。

C# 5個用於 類/類成員 的 影響組件版本控制 的 關鍵字:

abstract:用於類/類成員

virtual和override:用於成員

sealed:用於類/類成員。用於成員時,僅用於重寫了虛方法的方法。

new,用於類/類成員/常量/字段

C#調用虛方法:

CLR允許類中定義多個"同名方法",僅僅是返回類型不同,IL允許這樣做;C#不允許,忽略返回值的類 型,相應的用"轉換操作符"實現IL中的"同名方法"。

調用方法相應的MSIL:

一個是call,用來調用靜態方法,實例方法和虛方法。必須要指定調用方法的類型(對於靜態方法)或 者對象(對於實例方法/虛方法),如果在該類型/對象中找不到該方法,會檢查其基類來匹配方法。

另一個是callvirt,用來調用實例方法和虛方法,不能用於調用靜態方法。必須要指定調用方法的實 例對象,如果這個對象為null,會拋出NullReferenceException異常,這意味著每次調用前都會有額外的 null檢查,從而比調用call慢一些。

如下代碼所示:

    public sealed class Program

    {

        public Int32 GetFive()

        {

            return 5;

        }


        public static void Main()

        {

            Program p = null;

            Int32 x = p.GetFive();  //在C#中,使用callvirt,會拋出

NullReferenceException異常

        }

    }

在C#編譯器中,使用callvirt調用所有實例方法(包括虛方法),使用call調用所有靜態方法。對於其 他的編譯器,這一點不能保證,所以在虛方法和非虛方法之間改動而不重新編譯,會產生無法預測的問題 。

C#使用call而不用callvirt調用虛方法的特例:ToString,見下:

    internal class SomeClass

    {

        public override string ToString()

        {

            return base.ToString();

        }

    }

這時候,生成call的IL代碼。因為如果使用callvirt,意味著這時一個虛方法,從而遞歸執行該方法 ,直到AppDomain的堆棧溢出。

在調用值類型定義的方法時,使用call。這是因為,首先,值類型是密封的,從而不存在虛方法;另 外,值類型永遠不會為null,所以永遠不會拋出NullReferenceException異常;再者,如果使用callvirt ,就要使用裝箱機制,性能會有極大影響。

在設計class的過程中,要盡量少定義虛方法。取代辦法:可以定義一組重載方法,經其中最復雜的方 法虛擬化,而將所有有用的重載非虛擬化,示例如下:

    public class Set

    {

        private Int32 m_length = 0;


        //這個有用的重載是非虛擬的

        public Int32 Find(Object value)

        {

            return Find(value, 0, m_length);

        }

        //這個有用的重載是非虛擬的

        public Int32 Find(Object value, Int32 startIndex)

        {

            return Find(value, 0, m_length - startIndex);

        }
        //功能最豐富的方法是虛擬的,可以被重寫

        public Int32 Find(Object value, Int32 startIndex, Int32 endIndex)

        {

            .//具體實現

        }

    }

sealed密閉類盡量使用。將sealed改為非密閉的容易,反之困難;性能也快,因為sealed一定是非虛 擬的,從而編譯器不用考慮其派生類,而虛方法的性能不如非虛方法;因為密閉了,所以安全性和可預測 性也就高。

子類中有父類的方法,會警告,不會報錯。這時要使用new關鍵字,告訴CLR,新舊方法沒有任何關系 。

補充:

1.靜態成員是在堆上分配的。CLR在創建TYPE對象的時候,靜態數據成員也會創建

2.實例類中可以有靜態成員

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