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