| 編譯器開關設置 | IL代碼質量 | JIT本地代碼質量 |
| /optimize- /debug-(默認設置) | 未優化 | 優化 |
| /optimize- /debug+(full/pdbonly) | 未優化 | 未優化 |
| /optimize+ /debug+(/-/full/pdbonly) | 優化 | 優化 |
?GetType()為非虛方法,所以其他類型不能改變這個這個函數的返回值
從值類型調用GetType()會有一次裝箱,以將【對象類型指針】指向對應的類型(type)對象
【對象類型指針】:在CLR via C#上有講,比較清楚,堆上的對象所需要的開銷字段之一,另一個是同步塊索引
?Equal方法,重寫Equal,IEquatble<T>
Equal方法是判斷相等性,CLR via C#書上說的Object的Equal實例方法只是簡單調用==運算符,判斷的是一致性(identity),即和靜態方法ReferenceEqual一樣,我那Reflector看,最后調用的RuntimeHelper extern方法,怎么實現的也不得而知.
所有的值類型,如Struct繼承自System.ValueType,重寫的Equal如下

1 [SecuritySafeCritical, __DynamicallyInvokable] 2 public override bool Equals(object obj) 3 { 4 if (obj == null) 5 { 6 return false; 7 } 8 RuntimeType type = (RuntimeType) base.GetType(); 9 RuntimeType type2 = (RuntimeType) obj.GetType();10 if (type2 != type)11 {12 return false;13 }14 object a = this;15 if (CanCompareBits(this))16 {17 return FastEqualsCheck(a, obj);18 }19 FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);20 for (int i = 0; i < fields.Length; i++)21 {22 object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);23 object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);24 if (obj3 == null)25 {26 if (obj4 != null)27 {28 return false;29 }30 }31 else if (!obj3.Equals(obj4))32 {33 return false;34 }35 }36 return true;37 }38 39 40 41 View Code 通過比較值,我們來看看int結構的源碼
上面一個object類型參數的是重寫繼承自ValueType的Equals,下面那個是實現IEquatable<int>接口
調用的是int的==的操作符,==默認比較的引用,在ValueType類中沒有找到任何重載運算符的code,對于這個==操作符,在園子搜到的說是值類型==比較值,引用類型==比較引用,在自定義值類型如果不重載==運算符,就無法使用==運算符
Summary:對于我們自定義類型,如果要重寫Equals,也重寫下GetHashCode(),這個GetHashCode在HashTable,Dictionary中用來存儲,索引鍵,同時可以實現IEquatable<T>接口,在override的Equals中調用這個參數為T的方法.要是參與比較,可以實現IComparable<int>,可以供Equals,以及運算符重載(> >= < <=)使用
參考http://msdn.microsoft.com/zh-cn/library/ms173147.aspx
Object o=new Person();//可以自動將new出來的Person隱式轉換Person類的任何基類
Person p=(Person)o;//強制類型轉換,顯式指定,可將一個實例強制轉換為new 類型,以及該構造類型的基類
上面的轉化在Base class,Derived class之間的轉換,不需要編寫額外的代碼.
這倆單詞總是記不住,搞混,上面的轉換是不需要code的,在不能轉換的時候,會拋出InvalidCastException,但有的時候,我們就知道怎么在不相關的實例中轉換,需要在代碼中給出轉換方法
public static implicit Operator 轉換到的類型(原類型)//implicit可以在本類里面互轉
public static implicit operator ClassA(ClassB b);//將ClassB隱式轉換為ClassA
public static implicit operator ClassB(ClassA a);//將ClassA隱式轉換為ClassB
這兩個轉換都可以在一個類中完成
public static explicit operator 轉換到的類型(本類型-即當前類)
如果要將ClassA轉為ClassB
只能在ClassA里面定義public static explicit operator ClassB(ClassA a);//顯式轉換要求被轉類型必須是當前類
msdn:http://msdn.microsoft.com/zh-cn/library/z5z9kes2.aspx
abc as ABC等價于(abc is ABC) ?(ABC)abc :null
之前寫代碼的時候,總是想,as 和 is是哪個調用哪個呢,其實as調用is,再加強制類型轉換
我以前喜歡這樣寫
if(abc is ABC){ abc as ABC; blabla...}
其實我這樣寫判斷了兩次abc的類型,再if里面直接用強制類型轉換即可
定義struct可以看到有System.InteropServices.StructLayoutAttribute(LayoutKind.xxx)出現
這個特性可以決定CLR如何排列類 or 結構 中的字段,
Sequential:讓CLR保持字段的排列;
Auto:讓CLR來優化處理,可能會被壓縮,分組等;
Explicit:顯式地指出偏移量,來決定如何排列
結構體(Struct)默認為Sequential,經常用于與非托管C/C++代碼打交道,如果確定不用于與非托管代碼交互,可改為Auto來讓CLR優化性能
類默認就是Auto,CLR優化
call用來調用
?靜態方法,指定類型,方法
?實例方法,call調用實例方法時,會假設變量!=null
?特殊情況下的虛方法,非虛擬的調用虛方法,下文解釋
callvirt
?非虛實例方法,callvirt會檢查當前實例是否為null,如果是,會拋出NullReferenceException
?虛方法,call virtual,應該就是這個的縮寫,調用一個虛方法時,會查找對象的實際類型,多方面地調用虛方法...
這個說的也是文鄒鄒的,調用虛方法
1.如果是ABC abc=new ABC類型的,從該類以及父類中尋找被調用的方法,比較常規
2.像Base instance=new Derived(),父類聲明,new 子類的情況,是從父類Base中開始尋找,如果找到,而且標記為virtual,而且子類中有相應的override,就調用子類的override實現,就是所謂的多態了.
在call中的第三條,call 虛方法,是這樣一種情況:在C#編譯器已知本次方法調用不會有多態存在的情況下,會生成call 虛方法指令,
例如
class Abc{ public override void ToSTring() { return base.ToString();//本行代碼會生成call指令,調用ToString()虛方法 }}
這個類Abc繼承自Object,重寫了ToString方法,在return base.ToSTring()時如果再用callvirt Object的ToString時,會導致遞歸調用,直至棧溢出,所以當不存在多態的情況下,虛方法調用也會生成call指令,再一個常見的是自己寫一個Struct,override一個方法,然后調用一下,絕壁生成的call,因為結構體不允許繼承,所以也沒有誰來override它的方法
委托,事件,lambda表達式,都是很常用的東西.
委托,類似函數指針,定義一個委托之后,會被編譯成一個類,繼承自MulticastDelegate,這個MulticastDelegate又繼承自Delegate類
委托中有三個私有字段
_target 表示目標,如果委托代表的是靜態函數,那么_target即為null,若是實例成員,則_target即為這個實例
_methodPtr 函數指針,指向所代表的函數
_invocationList 表示執行鏈,當委托只是代表著一個函數時,此字段為空
委托暴露兩個公開屬性
Target:對應上面的_target
Method : MethodInfo類型,表示委托代表的函數
委托編譯成的類,會有一個構造方法(Object target,Intptr method)
一個Invoke函數,執行這個委托,還有BeginInvoke,EndInvoke 異步編程模式里面通用的
多播委托
Delegate.Combine/Delegate.Remove 可以將兩個委托連起來/剔除
而且重載了+=,-=運算符,以快速調用
在一個委托被combine了很多其他簽名符合的委托時,_target,_method均不重要了,也就是不會被調用了,而它的invocationList是被連接過的委托數組,代表著執行鏈,當委托執行時,會依次執行,但不能保證執行順序
委托語法糖
1.不需要new 委托類型(方法)了,可以直接 +=方法名
2.delegate(參){}匿名方法的出現,可以省去定義方法的步驟,以及lambda表達式,太方便了
3.delegate{},可以省去參數,當你不關心參數時,可以連括號都不用,例如在WinForm this.btn.Click+=delegate{ MessageBox(xxx);};
4.閉包支持,即在匿名方法內部可以訪問外部變量
屬性,get;set;訪問器也沒什么好說的.在書中,將索引器indexer叫做有參屬性
TValue this[TKey key] { [__DynamicallyInvokable] get; [__DynamicallyInvokable] set; }
這是IDictionary<TKey,TValue>接口的索引器
如果有一個IIDictionary<TKey,TValue>實例,dict
默認如果可以用dict["key"],或者dict.Items["key"]
為什么是這個Items呢,在索引器上可以有一個IndexerNameAttribute("ABC"),那樣就可以用dict.ABC["key"]來訪問,
因為屬性,索引器最后都會生成方法,來調用,編譯器可以根據這個Attribute來生成方法名稱
新聞熱點
疑難解答