C#學習筆記四: C#3.0自動屬性匿名屬性及擴展方法

前言

這一章算是看這本書最大的收獲了, Lambda表達式讓人用著屢試不爽, C#3.0可謂顛覆了我們的代碼編寫風格. 因為Lambda所需篇幅挺大, 所以先總結C#3.0智能編譯器給我們帶來的諸多好處, 下一遍會單獨介紹Lambda表達式. 這篇主要包括的內容有:?自動屬性,隱式類型,對象集合初始化,匿名類型,擴展方法.

下面一起來看下C#3.0 所帶來的變化吧.

1,自動實現的屬性
在C#3.0之前, 定義屬性時一般會像下面這樣去編寫代碼:

 1 class Person
 2 {
 3     //定義私有字段
 4     private string name;
 5 
 6     //定義可讀寫屬性
 7     public string Name
 8     {
 9         get{return name;}
10         set{name = value;}
11     }
12 
13     private int age;
14     //定義只讀屬性
15     public int Age
16     {
17         get{return age;}
18     }
19 }
View Code

PS: 這里有一個快捷鍵: private string name; 選中name 然后Ctrl + R + E 就可以快捷生成Name屬性.

C#3.0之后, 對于不需要額外驗證的屬性(需要額外驗證的屬性還是必須采用之前的方式來定義), 我們可以使用自動實現的特性來對屬性的定義進行簡化, 此時不再需額外定義一個私有字段了.代碼如下:

1 class Person
2 {
3     //使用自動實現的屬性來定義屬性
4     //定義可讀寫屬性
5     public string Name{get; set;}
6     //定義只讀屬性
7     public int Age{get; private set;}
8 }
View Code

PS: 這里也有一個快捷鍵: 打出prop 然后點擊兩下Tab鍵就可以生成上面的屬性了, 不過還需手動改值.?
類似的快捷鍵有: 輸入cw 然后點擊兩下Tab鍵 就可以直接生成Console.WriteLine();了. 類似的還有很多, 在這里就不列舉了.

之所以可以這樣定義屬性, 主要是因為編譯器在編譯時會為我們創建一個私有字段. 利用反編譯工具可以知道使用自動實現的屬性時,C#都會幫我們創建必要的字段.
另外在結構體中使用自動屬性時, 需要注意的是所有構造函數都需要顯式地調用無參構造函數this, 否則會出現編譯錯誤. 因為只有這樣,編譯器才能知道所有的字段都已經被賦值.
然而, 類卻不需要顯式地調用無參構造函數, 這主要是由C#編譯器的設計決定, 我們記住就好了.

 1 public struct TestPerson
 2 {
 3     public string Name { get; set; }
 4     public int Age { get; private set; }
 5 
 6     //結構體中, 不顯式地調用無參構造函數this()時, 會出現編譯時錯誤
 7     public TestPerson(string name)
 8     : this()
 9     {
10         this.Name = name;
11     }
12 }
View Code

2,隱式類型 var關鍵字
C#是強類型語言, 在定義一個變量時, 需要聲明變量的類型. 然而類型的長度過長,就可能影響代碼的可讀寫性. 為了避免這樣的問題, C#3.0 引入了隱式類型,即可以使用關鍵字var來聲明變量或數組.
var關鍵字告訴編譯器去根據變量的值來推斷其類型.

1 class Program
2 {
3     static void Main(stirng[] args)
4     {
5         //用var聲明局部變量
6         var stringValue = "Barry Wang";
7         stringValue = 2;
8     }
9 }
View Code

這里就會報錯"無法將類型int 隱式轉換為string". 調試會發現stringValue是string類型的.
使用隱式類型有一些限制, 包括以下幾點:
(1)被聲明的變量是一個局部變量, 不能為字段
(2)變量在聲明時必須被初始化, 因為編譯器要根據變量的賦值來推斷類型
(3)變量不能初始化為一個方法組, 也不能為一個匿名函數

3,對象集合初始化
在C#3.0之前定義類, 我們往往需要定義多個構造函數來完成不同情況下的初始化, C#3.0 提供了對象初始化器, 它減少了我們在類中定義的構造函數代碼, 從而使代碼更加簡潔.

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     { 
 5         //沒有對象初始化器時的代碼
 6         Person p = new Person("BarryWang", 25);
 7         p.Weight = 60;
 8         p.Height = 170;
 9     }
10 }
11 
12 public class Person
13 {
14     public string Name { get; set; }
15     public int Age { get; set; }
16     public int Weight { get; set; }
17     public int Height { get; set; }
18 
19     //定義不同情況下的初始化函數
20     public Person() { }
21     public Person(string name) { } 
22     public Person(string name, int age) { }
23     public Person(string name, int age, int weight) { }
24     public Person(string name, int age, int weight, int height) 
25     {
26         this.Name = name;
27         this.Age = age;
28         this.Weight = weight;
29         this.Height = height;
30     }
31 }
View Code

在C#3.0引入對象初始化之后, 我們就不需要定義多個構造函數了, 前面的代碼可以簡化為如下的形式:

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         //使用對象初始化器初始化
 6         Person p = new Person() {Name = "Barry Wang", Age = 25, Weght = 60, Height = 70};
 7         //下面這行代碼和上面一行是等價的, 只不過下面省略了構造函數的圓括號而已
 8         Person p2 = new Person {Name = "Barry Wang", Age = 25, Weght = 60, Height = 70};
 9     }
10 }
11 
12 public class Person
13 {
14     public string Name { get; set; }
15     public int Age { get; set; }
16     public int Weight { get; set; }
17     public int Height { get; set; }
18 }
View Code

利用反編譯工具可以知道編譯器為對象做了如下處理: 首先C#編譯器生成了一個Person類的臨時對象, 并調用Person類的默認無參構造函數對其初始化.然后對它的屬性逐個賦值.
由此可以想到,要使用對象初始化器,則必須保證類中具有一個無參構造函數. 如果我們自定義了一個有參構造函數而把默認的無參構造函數覆蓋了, 則需要重新定義一個無參構造函數.

再例如 給List 中添加元素, 在C#3.0 之前我們需要一個個Add 添加, 而現在直接可以利用集合初始化器即可, 編譯器會調用Add方法, 一個個地將初始化的內容添加進去.

1 class Program
2 {
3     List<string> newNames = new List<string>
4     {
5         "A", "B", "C"
6     };
7 }
View Code

4,匿名類型
匿名類型顧名思義就是沒有知名類型的類型, 通過隱式類型和對象初始化器兩種特性創建了一個類型未知的對象, 使我們在不定義類型的情況下可以實現對象的創建,從而減少了類定義過程的代碼.

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     { 
 5         //定義匿名類型對象
 6         var person = new {Name = "Barry Wang", Age = 25 };
 7         Console.WriteLine("{0} 的年齡為: {1}", person.Name, person.Age);
 8 
 9         //定義匿名類型數組
10         var personCollection = new[]
11         {
12             new {Name = "Barry", Age = 30},
13             new {Name = "Brad", Age = 22},
14             new {Name = "Tony", Age = 25}
15         };
16 
17         int totalAge = 0;
18         foreach (var p in personCollection)
19         {
20             //下面一行代碼證明了Age屬性時int類型
21             totalAge += p.Age;
22         }
23 
24         Console.WriteLine("所有人的年齡總和為: {0}", totalAge);
25         Console.ReadKey();
26     }
27 }
View Code

5,擴展方法
擴展方法, 首先是一個方法, 他可以用來擴展已定義類型中的方法成員.
如下例所示:

 1 public static class Extensions
 2 {
 3     //對string 類擴展,注意this關鍵字
 4     public static void TestStr(this string s)
 5     {
 6         Console.WriteLine(s.ToString());
 7     }
 8     //對int 類擴展
 9     public static void TestInt(this int i, string s)
10     {
11         Console.WriteLine(s + i.ToString());
12     }
13 }
14 class Program
15 {
16     static void Main(string[] args)
17     {
18         //使用擴展方法
19         string s = "Test Extensions Methods";
20         s.TestStr();//調用方法1
21         Extensions.TestStr(s);//調用方法2
22         int i = 100;
23         i.TestInt("This value is ");
24         Extensions.TestInt(i, "This value is ");
25         Console.ReadKey();
26     }
27 }
View Code

并不是所有的方法都可以用作擴展方法, 我們需要考察它是否符合下列擴展方法的定義規則:
(1)擴展方法必須在一個非嵌套, 非泛型的靜態類中定義
(2)它至少要有一個參數
(3)第一個參數必須加上this關鍵字作為前綴(第一個參數類型也稱為擴展類型, 即指方法對這個類型進行擴展)
(4)第一個參數不能使用任何其他修飾符(如不能使用ref out等)

 1 namespace CurrentNameSpace
 2 {
 3     //要想使用不用命名空間下的擴展方法, 需要先引入該命名空間
 4     using CustomNameSpace;
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             Person p = new Person {Name = "BarryWang"};
10             p.Print();//等價于==>ExtensionClass.Print(p);
11             p.Print("Hello");
12             Console.ReadKey();
13         }
14     }
15 
16     //自定義類型
17     public class Person
18     {
19         public string Name { get; set; }
20     }
21 
22     //當前命名空間下的擴展方法定義
23     public static class ExtensionClass
24     {
25         public static void Print(this Person p)
26         {
27             Console.WriteLine("調用的是當前命名空間下的擴展方法輸出, 姓名為: {0}", p.Name);
28         }
29     }
30 }
31 
32 namespace CustomNameSpace
33 {
34     using CurrentNameSpace;
35     public static class CustomExtensionClass
36     {
37         //擴展方法定義
38         public static void Pint(this Person p)
39         {
40             Console.WriteLine("調用的是CustomNameSpace命名空間下擴展方法輸出: 姓名為: {0}", p.Name);
41         }
42 
43         //擴展方法定義
44         public static void Pint(this Person p, string s)
45         {
46             Console.WriteLine("調用的是CustomNameSpace命名空間下擴展方法輸出: 姓名為: {0},附加字符串為{1}", p.Name, s);
47         }
48     }
49 }
View Code

打印結果是:
調用的是當前命名空間下的擴展方法輸出, 姓名為: Barry Wang
調用的是CustomNameSpace命名空間下擴展方法輸出, 姓名為: Barry Wang, 附加字符串為Hello

注解: 大家看到p.Print(); 是否有些疑惑呢? 對于C#3.0編譯器而言, 當它看到某個類型的變量在調用方法時, 它會首先去該對象的實例方法進行查找,如果沒有找到與調用方法同名并參數一致的實例方法,
編譯器就回去查找是否存在合適的擴展方法. 編譯器會檢查所有導入的命名空間和當前命名空間中的擴展方法, 并將變量類型匹配到擴展類型.
從編譯器發現擴展方法的過程來看, 方法調用的優先級別順序為: 類型的實例方法-->當前命名空間下的擴展方法-->導入命名空間的擴展方法.

解釋上面代碼打印結果的由來: 在以上代碼中存在另個不同的命名空間, 它們都定義了帶一個參數的擴展方法Print. 根據執行順序, 編譯器會首先查看Person類型中是否定義了無參的Print實例方法.
如果有, 則停止查找; 否則繼續查找當前命名空間下, 即CurrentNameSpace下是否定義了一個帶參數的擴展方法Print.
此時在CurrentNameSpace命名空間下, 正好存在帶一個擴展類型參數的Print擴展方法, 編譯器因此不會再繼續查找其他引入命名空間了. 所以p.Print() 調用的是當前命名空間下的Print擴展方法.
而p.Print("Hello")的調用也是一個道理.

轉載于:https://www.cnblogs.com/xinhuawei/p/5409275.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396240.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396240.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396240.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

array keys php,php array_keys與array_search的簡單使用

函數說明array_keys():返回數組中所有的鍵名。array_search():在數組中搜索給定的值&#xff0c;如果成功則返回相應的鍵名。//根據一個key返回關聯數組中的另一個key,并且不使用foreach// function array_key_relative(array $array, string $current_key, int $offset)functi…

RESTful服務的第三部分:HATEOAS和Richardson成熟度模型

by Sanchit Gera通過Sanchit Gera RESTful服務的第三部分&#xff1a;HATEOAS和Richardson成熟度模型 (RESTful Services Part III : HATEOAS and The Richardson Maturity Model) In Part I of this series, you learned the very basics of HTTP. We went over common HTTP …

mongdb集群3.4 shard 模式

從圖中可以看到有四個組件&#xff1a;mongos、config server、shard、replica set。mongos&#xff1a;數據庫集群請求的入口&#xff0c;所有的請求都通過mongos進行協調&#xff0c;不需要在應用程序添加一個路由選擇器&#xff0c;mongos自己就是一個請求分發中心&#xff…

我想變得富有的10個理由

1.我想和娘家人住得近一些&#xff0c;可以經常見面、聊天、逛街、吃飯。我們需要彼此的時候&#xff0c;可以馬上趕到。 2.我想在家人病痛的時候&#xff0c;能得到最好的救治。 3.我想住在干凈寬敞的大房子里&#xff0c;不要和長輩住^_^ 4.我希望不用我動手&#xff0c;家里…

alpha值計算 qcolor_量化交易與機器學習(四):如何研究alpha因子

算法交易策略由指示何時購買或出售資產以產生相對于基準&#xff08;例如指數&#xff09;的較高回報的信號驅動。 資產回報率中未通過暴露于該基準而無法解釋的部分稱為alpha&#xff0c;因此旨在產生這種不相關收益的信號也稱為alpha因子。本章主要介紹alpha因子一、從數據到…

項目啟動及需求分析(靳嘉豪、胡新宇、李晨曦、楊航、李瑤)團隊作業

&#xff08;1&#xff09; 這次團隊我們給我們團隊起的名字是&#xff1a;橋上吊刀刀倒吊著 隊員分別為&#xff1a;靳嘉豪、胡新宇、李晨曦、李瑤、楊航。 隊訓為&#xff1a;黑化肥揮發發灰會揮發。 胡新宇&#xff1a;http://www.cnblogs.com/hxy94264/ 靳嘉豪&#xff1a;…

java兩種傳參,有關java參數的兩種傳遞機制

值傳遞&#xff1a;方法調用時&#xff0c;實際參數把它的值傳遞給對應的形式參數&#xff0c;方法執行中形式參數值的改變不影響實際參 數的值。引用傳遞&#xff1a;也稱為傳地址。方法調用時&#xff0c;實際參數的引用(地址&#xff0c;而不是參數的值)被傳遞給方法中相對應…

tcp選項部分編碼_學習編碼中最難的部分也是最有趣的部分

tcp選項部分編碼by Corey Slaven通過Corey Slaven 學習編碼中最難的部分也是最有趣的部分 (The hardest part of learning to code is also the funnest part) “The more you know, the more you know you don’t know.”“知道的越多&#xff0c;知道的越多。” ― Aristotl…

SCU 4439 Vertex Cover(二分圖最小覆蓋點)題解

題意&#xff1a;每一條邊至少有一個端點要涂顏色&#xff0c;問最少涂幾個點 思路&#xff1a;最小頂點覆蓋&#xff1a;用最少的點&#xff0c;讓每條邊都至少和其中一個點關聯&#xff0c;顯然是道裸最小頂點覆蓋題&#xff1b; 參考&#xff1a;二分圖 代碼&#xff1a; #i…

20155229 實驗一《Java開發環境的熟悉》實驗報告

20155229 實驗一《Java開發環境的熟悉》實驗報告 實驗內容 1.使用JDK編譯、運行簡單的Java程序&#xff1b; 2.使用Idea 編輯、編譯、運行、調試Java程序。 實驗步驟 &#xff08;一&#xff09;命令行下Java程序開發 輸入 mkdir 20155229命令建立實驗目錄&#xff0c;用ls查看…

js時間搓化為今天明天_js轉時間戳,時間戳轉js

js轉時間戳轉此時此刻的時間1、var timestamp1 (new Date()).valueOf();valueOf() 方法返回指定對象的原始值2、var timestamp2 new Date().getTime();Date.prototype.getTime()方法的返回值一個數值&#xff0c;表示從1970年1月1 日0時0分0秒(UTC&#xff0c;即協調世界時)距…

PHP代碼20個實用技巧(轉)

這些技巧特別是封裝的&#xff0c;相對路徑的還是挺好的&#xff0c;本身來自微信公眾號&#xff0c;但是我擔心以后刪除&#xff0c;所以在我的博客上備份一下&#xff08;微信公眾號為:菜鳥教程&#xff09; 在這篇文章中我們將看看一些關于PHP開發有用的提示和技巧&#xff…

需求簡報_代碼簡報:NASA將所有研究成果發布為開放數據

需求簡報Here are three stories we published this week that are worth your time:這是我們本周發布的三個值得您關注的故事&#xff1a; With open data, you finally get what you’ve paid for all these years: 4 minute read 有了開放的數據&#xff0c;您終于可以得到…

matlab 16位灰度值轉8位,在matlab中如何將灰度值為24位的轉化為8?

我使用的是Visual c6。0技術內幕里提供的類CDib來操作位圖&#xff0c;最好提供可以兩個獨立的函數來分辨別實現著倆個功能。他們可以作為CDib類的成員函數來使用。類似下面的這個就可以&#xff0c;我用了下面的這個&#xff0c;但是下面這個不好用&#xff0c;處理后的圖象有…

quartz基本使用

創建一個任務調度 Scheduler scheduler StdSchedulerFactory.getDefaultScheduler();//Schedulers can be immediately used to schedule jobs, but they will not start executing any until the .start()scheduler.start();//And then schedule those jobs with triggers th…

em模型補缺失值_基于EM算法數據單變量缺失處理方法研究

龍源期刊網http://www.qikan.com.cn基于EM算法數據單變量缺失處理方法研究作者&#xff1a;黃鉉來源&#xff1a;《科技傳播》2015年第20期摘要數據分析方法大都針對完整數據&#xff0c;而實際上由于一些原因&#xff0c;觀測數據常存在缺失。本文采用EM算法對正態分布下的隨機…

流媒體協議介紹(rtp/rtcp/rtsp/rtmp/mms/hls)

RTP 參考文檔 RFC3550/RFC3551 Real-time Transport Protocol)是用于Internet上針對多媒體數據流的一種傳輸層協議。RTP協議詳細說明了在互聯網上傳遞音頻和視頻的標準數據包格式。RTP協議常用于流媒體系統&#xff08;配合RTCP協議&#xff09;&#xff0c;視…

我從#100DaysOfCode中學到的東西

by E. Wilson由E. Wilson 我從&#xff03;100DaysOfCode中學到的東西 (What I learned from #100DaysOfCode) I made it up to Day 95 before officially ending my #100DaysOfCode challenge. Check out my GitHub repo and see for yourself.在正式結束&#xff03;100Days…

mysql 表ful,你所不知的table is full那些事

當我們要寫入新數據而發生“The table is full”告警錯誤時&#xff0c;先不要著急&#xff0c;按照下面的思路來逐步分析即可&#xff1a;1、查看操作系統以及MySQL的錯誤日志文件確認操作系統的文件系統沒有報錯&#xff0c;并且MySQL的錯誤日志文件中是否有一些最直觀的可見…

Calendar、Date、long類型的時間,三者之間如何轉化

1. Calendar類型轉化為Date類型和long類型 Calendar calendarCalendar.getInstance(); Date datecalendar.getTime(); long timecalendar.getTimeInMillis(); 2.Date類型轉化為Calendar類型和long類型 Date datenew Date(System.currentTimeMillis()100000000); Calendar calen…