C# 值類型的實(shí)現(xiàn)
1、c#類型
類型(Type)又叫數(shù)據(jù)類型(Data Type)。
A data type is a homogeneous collection of values,effectively prensented,equipped with a set of operations which manipulate these values.
- 數(shù)據(jù)類型是由相同類型的值組成的集合。比如int[]是整數(shù)的集合。
- 數(shù)據(jù)類型配備有專門針對(duì)自己的值的一組運(yùn)算操作,比如int類型的數(shù)據(jù)可以進(jìn)行加法、減法、乘法、除法操作。深層的意思是,這一組操作是專門為這一種數(shù)據(jù)類型準(zhǔn)備的,我們不能拿數(shù)據(jù)類型A的操作去對(duì)數(shù)據(jù)類型B進(jìn)行操作。
- 數(shù)據(jù)類型的“類型”二字包含有“型號(hào)”的意思,也就是說(shuō),一個(gè)數(shù)據(jù)類型代表著這種數(shù)據(jù)類型的值在內(nèi)存中存儲(chǔ)時(shí)需要占多少的內(nèi)存,比如對(duì)于int來(lái)說(shuō),它可存儲(chǔ)-2,147,483,648 到 2,147,483,647范圍內(nèi)的值,需要占4個(gè)字節(jié)。我們?cè)诖鎯?chǔ)數(shù)據(jù)時(shí),應(yīng)該選擇合適的數(shù)據(jù)類型,比如我們想要存儲(chǔ)100這個(gè)數(shù)據(jù),如果使用int的話顯得太浪費(fèi)了,使用byte就夠用了,byte只占一個(gè)字節(jié);而如果我們想要存儲(chǔ)256這個(gè)數(shù)據(jù),使用byte就不行了,因?yàn)閎yte只能存儲(chǔ)0~255的整數(shù)。所以說(shuō),大內(nèi)存存儲(chǔ)小尺寸的數(shù)據(jù)會(huì)導(dǎo)致浪費(fèi),小內(nèi)存存儲(chǔ)大尺寸的數(shù)據(jù)會(huì)導(dǎo)致丟失精度。舉一個(gè)現(xiàn)實(shí)中的例子,有一個(gè)盒子,如果我們拿一個(gè)橡皮丟進(jìn)去,空間完全足夠而且還有很多空出來(lái)的空間沒(méi)有得到利用,而如果我們拿一把椅子丟進(jìn)去就不行了,這時(shí)候如果想強(qiáng)制丟進(jìn)去,只能把椅子的一部分放進(jìn)去,椅子就會(huì)被損壞了。
- 數(shù)據(jù)類型會(huì)被有效地表示,包括存儲(chǔ)在內(nèi)存中的位置、占內(nèi)存的大小、類型包含的成員(方法、字段、事件等)、類型所繼承的基類型。
- c#是一種強(qiáng)類型的語(yǔ)言,這意味著每個(gè)變量和常量都必須有一個(gè)明確的數(shù)據(jù)類型。這樣編譯器就能保證代碼中執(zhí)行的所有運(yùn)算都是類型安全的。例如,如果定義了一個(gè) int 類型的變量,則編譯器允許在加法和減法運(yùn)算中使用此變量, 如果嘗試在一個(gè) string 類型的變量上執(zhí)行相同的運(yùn)算,則編譯器會(huì)產(chǎn)生錯(cuò)誤。
// c#代碼 int a = 10; string str = "Hello, world!"; int b = a + str; //輸出結(jié)果為: //無(wú)法將類型“string”隱式轉(zhuǎn)換為“int”
# python代碼 a = 10 a = "Hello, world!"
c#類型分為值類型和引用類型,值類型有結(jié)構(gòu)體和枚舉,引用類型有類、接口、委托。
struct MyStruct // 定義結(jié)構(gòu)體 { } Type type = typeof(int); //使用typeof關(guān)鍵字獲取int的類型 Console.WriteLine(type.BaseType); //打印int的基類型 Console.WriteLine(type.BaseType.BaseType); //打印int的基類型的基類型 Console.WriteLine("---------"); type = typeof(MyStruct); //使用typeof關(guān)鍵字獲取MyStruct的類型 Console.WriteLine(type.BaseType); //打印MyStruct的基類型 Console.WriteLine(type.BaseType.BaseType); //打印MyStruct的基類型的基類型 //輸出結(jié)果為: //System.ValueType //System.Object //--------- //System.ValueType //System.Object
2、值類型
值類型的變量存儲(chǔ)數(shù)據(jù),而引用類型的變量存儲(chǔ)對(duì)實(shí)際數(shù)據(jù)的引用。
2.1 結(jié)構(gòu)體
結(jié)構(gòu)體和類很相似,結(jié)構(gòu)體通常用來(lái)封裝小型相關(guān)變量組。
與類相比,結(jié)構(gòu)體有一些限制,例如它不能聲明為抽象的或密封的,它也不能聲明默認(rèn)構(gòu)造函數(shù)(沒(méi)有參數(shù)的構(gòu)造函數(shù))和析構(gòu)函數(shù)。結(jié)構(gòu)體通常用于小型、不可變的數(shù)據(jù)結(jié)構(gòu),而類更適合用于需要更復(fù)雜行為的對(duì)象。
結(jié)構(gòu)體在C#中是實(shí)現(xiàn)輕量級(jí)數(shù)據(jù)結(jié)構(gòu)的強(qiáng)大工具,它在性能上通常優(yōu)于類,因?yàn)樗苊饬死厥盏拈_(kāi)銷。然而,它也有一定的限制,比如不能被聲明為可空的,并且當(dāng)結(jié)構(gòu)體包含引用類型字段時(shí),可能會(huì)引入垃圾回收的開(kāi)銷。
結(jié)構(gòu)體可以包含構(gòu)造函數(shù)、 常量、 字段、 方法、 屬性、 索引器、 運(yùn)算符、 事件和嵌套類型,但如果同時(shí)需要上述幾種成員,則應(yīng)當(dāng)考慮改為使用類作為類型。
struct Student { public int age; public int height; public double weight; public string name; }
我們不能在結(jié)構(gòu)體中初始化實(shí)例字段,可以在結(jié)構(gòu)體中初始化靜態(tài)字段以及常量。
struct Student { public static int avgAge = 10; //可以在結(jié)構(gòu)體中初始化靜態(tài)字段 public const int height = 100; //可以在結(jié)構(gòu)體中初始化常量 public int age; //不能在結(jié)構(gòu)體中初始化實(shí)例字段 }
要想初始化實(shí)例字段,有兩種方法:一是使用參數(shù)化構(gòu)造函數(shù),二是在聲明結(jié)構(gòu)后分別訪問(wèn)成員。
struct Student { public Student(int x) { age = x; } //public static int avgAge = 10; public int age; } Student stu = new Student(10); //使用參數(shù)化構(gòu)造函數(shù)初始化實(shí)例字段 Console.WriteLine(stu.age); stu.age = 20; //聲明結(jié)構(gòu)后訪問(wèn)實(shí)例字段 Console.WriteLine(stu.age); //輸出結(jié)果為: //10 //20
與類不同,結(jié)構(gòu)的實(shí)例化可以使用new運(yùn)算符,也可以不使用。如果使用的話,會(huì)創(chuàng)建該結(jié)構(gòu)的對(duì)象,并調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)不傳入?yún)?shù)的話,調(diào)用的是默認(rèn)構(gòu)造函數(shù),默認(rèn)構(gòu)造函數(shù)會(huì)對(duì)結(jié)構(gòu)體的成員進(jìn)行初始化;如果不使用的話,就不會(huì)調(diào)用構(gòu)造函數(shù),在初始化所有字段之前,字段將保持未賦值狀態(tài)且對(duì)象不可用。
struct Student { public int age; public int height; } Student stu1; //不使用new創(chuàng)建對(duì)象 Student stu2 = new Student(); //使用new創(chuàng)建對(duì)象,并調(diào)用構(gòu)造函數(shù)
struct Student { public int age; public int height; } Student stu1; //不使用new創(chuàng)建對(duì)象 Console.WriteLine(stu1.age); //輸出結(jié)果為: //使用了可能未賦值的字段"age"
所以正確的做法應(yīng)該是:
struct Student { public int age; public int height; } Student stu1; stu1.age = 10; stu1.height = 130; Console.WriteLine(stu1.age); Console.WriteLine(stu1.height);
struct Student { public int age; public int height; } Student stu2 = new Student(); Console.WriteLine(stu1.age); Console.WriteLine(stu1.height);
2.2 枚舉
枚舉類型用enum關(guān)鍵字進(jìn)行聲明,它是一種由一組稱為枚舉數(shù)列表的命名常量組成的獨(dú)特類型。
通常情況下,最好是在命名空間內(nèi)直接定義枚舉,以便該命名空間中的所有類都能夠同樣方便地訪問(wèn)它。 但是,還可以將枚舉嵌套在類或結(jié)構(gòu)中。
默認(rèn)情況下,第一個(gè)枚舉數(shù)的值為 0,后面每個(gè)枚舉數(shù)的值依次遞增 1。
namespace ConsoleApp1 { enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; class Program { static void Main(string[] args) { Console.WriteLine((int)Days.Mon); Console.WriteLine((int)Days.Tue); Console.WriteLine((int)Days.Wed); } } } //輸出結(jié)果為: //0 //1 //2
當(dāng)然,也可以強(qiáng)制元素序列從1開(kāi)始。
namespace ConsoleApp1 { enum Days { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun }; class Program { static void Main(string[] args) { Console.WriteLine((int)Days.Mon); Console.WriteLine((int)Days.Tue); Console.WriteLine((int)Days.Wed); } } } //輸出結(jié)果為: //1 //2 //3
枚舉類型的默認(rèn)基礎(chǔ)類型是int,所以,上述代碼中定義枚舉類型變量的完整表達(dá)為:
enum Days:int { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun };
枚舉類型變量可賦以基礎(chǔ)類型范圍內(nèi)的任何值,準(zhǔn)許使用的枚舉類型有 byte、 sbyte、 short、 ushort、 int、 uint、 long 或 ulong。
namespace ConsoleApp1 { enum Days:byte { Mon=1, Tue=2, Wed=10, Thu=20, Fri=30, Sat=100, Sun=255 }; class Program { static void Main(string[] args) { Console.WriteLine((byte)Days.Mon); Console.WriteLine((byte)Days.Tue); Console.WriteLine((byte)Days.Wed); Console.WriteLine((byte)Days.Thu); Console.WriteLine((byte)Days.Fri); Console.WriteLine((byte)Days.Sat); Console.WriteLine((byte)Days.Sun); } } } //輸出結(jié)果為: //1 //2 //10 //20 //30 //100 //255
在switch語(yǔ)句中使用枚舉值。
namespace ConsoleApp1 { enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; class Program { static void Main(string[] args) { Days day = (Days)1; switch (day) { case Days.Mon: Console.WriteLine("Today is Mon"); break; case Days.Tue: Console.WriteLine("Today is Tue"); break; case Days.Wed: Console.WriteLine("Today is Wed"); break; case Days.Thu: Console.WriteLine("Today is Thu"); break; case Days.Fri: Console.WriteLine("Today is Fri"); break; case Days.Sat: Console.WriteLine("Today is Sat"); break; case Days.Sun: Console.WriteLine("Today is Sun"); break; } } } }
使用枚舉類型的好處:
- 明確變量可以存儲(chǔ)的值。
enum Days:byte { Mon=1, Tue=2, Wed=10, Thu=20, Fri=30, Sat=100, Sun=255 }; Days day = Days.Mon;
在這個(gè)程序中,一個(gè)星期只能包含從星期一到星期日的7天,所以只能取枚舉中的值。
我們可以使用擴(kuò)展方法為枚舉類型添加功能。
namespace ConsoleApp1 { // 在非泛型靜態(tài)類中定義擴(kuò)展方法 public static class Extensions { public static Grades minPassing = Grades.D; // this關(guān)鍵字在方法定義中用于指定這是一個(gè)擴(kuò)展方法 //this關(guān)鍵字后面跟著的是類型參數(shù),表示這個(gè)擴(kuò)展方法可以被任何Grade類型的實(shí)例調(diào)用 public static bool Passing(this Grades grade) { return grade >= minPassing; } } public enum Grades { F = 0, D=1, C=2, B=3, A=4 }; class Program { static void Main(string[] args) { Grades g1 = Grades.D; Grades g2 = Grades.F; Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not"); Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not"); Extensions.minPassing = Grades.C; Console.WriteLine("\r\nRaising the bar!\r\n"); Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not"); Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not"); } } } } /* 輸出結(jié)果為: First is a passing grade. Second is not a passing grade. Raising the bar! First is not a passing grade. Second is not a passing grade. */
實(shí)際上,通過(guò)枚舉類型實(shí)例對(duì)擴(kuò)展方法的調(diào)用,等效于調(diào)用普通非擴(kuò)展方法的方式。也就是說(shuō),調(diào)用擴(kuò)展方法與調(diào)用在類型中實(shí)際定義的方法之間沒(méi)有明顯的差異。
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not"); Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not"); // 等效于 Console.WriteLine("First {0} a passing grade.", Extensions.Passing(g1) ? "is" : "is not"); Console.WriteLine("First {0} a passing grade.", Extensions.Passing(g2) ? "is" : "is not");
到此這篇關(guān)于C# 值類型的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C# 值類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# 操作 access 數(shù)據(jù)庫(kù)的實(shí)例代碼
這篇文章主要介紹了C# 操作 access 數(shù)據(jù)庫(kù)的實(shí)例代碼,需要的朋友可以參考下2018-03-03C#實(shí)現(xiàn)FTP文件下載及超時(shí)控制詳解
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)FTP文件下載及超時(shí)控制的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03C#實(shí)現(xiàn)創(chuàng)建標(biāo)簽PDF文件的示例代碼
標(biāo)簽PDF文件包含描述文檔結(jié)構(gòu)和各種文檔元素順序的元數(shù)據(jù),是一種包含后端提供的可訪問(wèn)標(biāo)記,管理閱讀順序和文檔內(nèi)容表示的邏輯結(jié)構(gòu)的PDF文件。本文將用C#實(shí)現(xiàn)創(chuàng)建標(biāo)簽PDF文件,需要的可以參考一下2022-08-08用幾行C#代碼實(shí)現(xiàn)定時(shí)關(guān)機(jī)/重啟(超詳細(xì)!建議新手練習(xí))
有很多的軟件都實(shí)現(xiàn)了自動(dòng)關(guān)機(jī)這樣的功能,下面這篇文章主要給大家介紹了關(guān)于利用幾行C#代碼實(shí)現(xiàn)定時(shí)關(guān)機(jī)/重啟的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12解析C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用
這篇文章主要介紹了C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用,外觀模式中分為門面(Facade)和子系統(tǒng)(subsystem)兩個(gè)角色來(lái)進(jìn)行實(shí)現(xiàn),需要的朋友可以參考下2016-02-02C#實(shí)現(xiàn)子窗體與父窗體通信方法實(shí)例總結(jié)
這篇文章主要介紹了C#實(shí)現(xiàn)子窗體與父窗體通信方法,實(shí)例總結(jié)了常用的四種窗體通信方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09C#中LinkedList<T>的存儲(chǔ)結(jié)構(gòu)詳解
這篇文章主要介紹了深度解析C#中LinkedList<T>的存儲(chǔ)結(jié)構(gòu),本文將從鏈表的基礎(chǔ)特性、C#中LinkedList的底層實(shí)現(xiàn)邏輯,.NET的不同版本對(duì)于Queue的不同實(shí)現(xiàn)方式的原因分析等幾個(gè)視角進(jìn)行簡(jiǎn)單的解讀,需要的朋友可以參考下2023-12-12C#中DataTable實(shí)現(xiàn)行列轉(zhuǎn)換的方法
這篇文章主要介紹了C#中DataTable實(shí)現(xiàn)行列轉(zhuǎn)換的方法,實(shí)例分析了C#操作DataTable的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04