1. 程式人生 > >c# 誤區系列(一)

c# 誤區系列(一)

### 前言 整理很早以前認為的一些誤區,準備整理一個系列。新手可以看下,然後大佬指點一下是否哪些地方錯了。 ### 正文 #### 值型別存在棧上,引用型別存在堆上 很多人認為用這句話來解釋值型別和棧型別的區別,甚至有些文章還公開這樣寫,把其看做是一種區別。 有這樣一個例子,比如說一個類中有一個int型別,請問這個int型別存在堆上還是棧上? 答案是存在堆上。 為什麼這麼說呢?原因是class的物件是一個引用型別,而類物件的變數的值總是和物件的其他資料在一起,那麼就是在堆上。 引用型別在堆上是沒有問題的,因為引用型別的確是在堆上建立的。 那麼下一個問題,就方法中的值型別存在堆上還是棧上? 存在棧上,那麼這個是為什麼呢? 因為在程式碼執行方法裡面的程式片段的時候,其實和類物件沒有直接關係,間接關係是類物件作為該方法執行的上下文的棧頂。 那麼問題來了,是否引用型別可以存在棧上?為什麼? #### int a=1;a.tostring()和 $"{a}"沒有區別? 這個問題是什麼時候會發生裝箱拆箱問題。 直接能看出裝箱和拆箱的就是:object o=a; 那麼隱式如何看出呢? 關鍵就是a 是否呼叫的是tostring() 是否是int 實現的還是object實現的。 ![](https://img2020.cnblogs.com/blog/1289794/202010/1289794-20201014140224038-439604888.png) 上面這些方法是值得注意的,是呼叫值型別的方法還是呼叫的是object 方法,決定是否裝箱。 那麼問題來了,a+"" 是否發生裝箱? #### linq中 from 子句中引用的資料來源的型別必須為 IEnumerable、IEnumerable<(Of <(T>)>) 或一種派生型別(如 IQueryable<(Of <(T>)>)) 其實這個真的不一定,以前我寫過一篇。 https://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;} } ``` 他們的本質沒有變化。 那麼為什麼使用屬性呢?而不是直接使用變數,這其實是程式設計思維的一個很大的變化。 屬性其實是一個介面,是這個物件暴露出去的,而不是直接操作了該物件,體現其封裝性。 也就是說該物件是一個盒子,而不是一個可直接操作的東西,任何操作都是在該物件允許的情況下: ![](https://img2020.cnblogs.com/blog/1289794/202010/1289794-20201015123043419-1710731764.png) 下面可以提現其介面性: ``` class person{ public stirng Name{get;private set;} } ``` 可以設定set 為私有來關閉修改,提現了物件的主導性,而不是呼叫者的主導性。 #### 結 持續更新中,應該有挺