c# 誤區系列(一)
- 2020 年 10 月 15 日
- 筆記
- c# 基礎(回憶錄)
前言
整理很早以前認為的一些誤區,準備整理一個系列。新手可以看下,然後大佬指點一下是否哪些地方錯了。
正文
值類型存在棧上,引用類型存在堆上
很多人認為用這句話來解釋值類型和棧類型的區別,甚至有些文章還公開這樣寫,把其看做是一種區別。
有這樣一個例子,比如說一個類中有一個int類型,請問這個int類型存在堆上還是棧上?
答案是存在堆上。
為什麼這麼說呢?原因是class的對象是一個引用類型,而類對象的變量的值總是和對象的其他數據在一起,那麼就是在堆上。
引用類型在堆上是沒有問題的,因為引用類型的確是在堆上建立的。
那麼下一個問題,就方法中的值類型存在堆上還是棧上?
存在棧上,那麼這個是為什麼呢?
因為在代碼運行方法裏面的程序片段的時候,其實和類對象沒有直接關係,間接關係是類對象作為該方法運行的上下文的棧頂。
那麼問題來了,是否引用類型可以存在棧上?為什麼?
int a=1;a.tostring()和 $”{a}”沒有區別?
這個問題是什麼時候會發生裝箱拆箱問題。
直接能看出裝箱和拆箱的就是:object o=a;
那麼隱式如何看出呢?
關鍵就是a 是否調用的是tostring() 是否是int 實現的還是object實現的。
上面這些方法是值得注意的,是調用值類型的方法還是調用的是object 方法,決定是否裝箱。
那麼問題來了,a+”” 是否發生裝箱?
linq中 from 子句中引用的數據源的類型必須為 IEnumerable、IEnumerable<(Of <(T>)>) 或一種派生類型(如 IQueryable<(Of <(T>)>))
其實這個真的不一定,以前我寫過一篇。
//www.cnblogs.com/aoximin/p/13727408.html
如果理解為必須IEnumerable,會陷入一個誤區,那就是比如說為了一些對象為了兼容linq,而去實現IEnumerable,這些是完全沒有必要。
然後還要一個問題就是,做排序sort用IComparer。IComparer之所以出現,是因為當時需要規範化,裏面可以去調用對應的方法進行比較。
但是隨着泛型和lambda的出現,一般都是這樣寫IEnumerable.sort((x,y)=>{
return x.age>y.age;
});
這樣的代碼更好維護,因為你不比再去關心IComparer(比較器)的修改。IComparer當然具有存在的價值,比如說複雜的比較,復用性也好一點。
屬性是變量?
初學的時候,可能有的有吧屬性當做變量。
比如說
class person{
public stirng Name{get;set;}
}
因為可以像調用變量一樣使用,所有會對屬性產生一些誤解。
那麼看下歷史吧:
第一版:
class person{
private string name;
private string Name{
get{return name;}
set{name=value;}
}
}
然後就是:
class person{
private string name;
private string Name{
get;set;
}
}
命名的規範就去掉了一些不必要的操作。
然後就是:
class person{
public stirng Name{get;set;}
}
他們的本質沒有變化。
那麼為什麼使用屬性呢?而不是直接使用變量,這其實是編程思維的一個很大的變化。
屬性其實是一個接口,是這個對象暴露出去的,而不是直接操作了該對象,體現其封裝性。
也就是說該對象是一個盒子,而不是一個可直接操作的東西,任何操作都是在該對象允許的情況下:
下面可以提現其接口性:
class person{
public stirng Name{get;private set;}
}
可以設置set 為私有來關閉修改,提現了對象的主導性,而不是調用者的主導性。
結
持續更新中,應該有挺多的。