C#?中值類型的實現(xiàn)示例
值類型和引用類型是 C# 類型系統(tǒng)的兩大支柱。值類型變量"直接裝數(shù)據(jù)",引用類型變量"裝數(shù)據(jù)地址"——這看似簡單的差別,卻深刻影響著賦值、傳參、方法返回的行為。這篇來徹底拆解。
- 核心行為:值類型復制的是數(shù)據(jù)實例本身
- 重要警告:值類型包含引用類型成員時的"淺復制"陷阱
- 值類型的三種種類:結(jié)構(gòu)、枚舉、聯(lián)合聲明
- 簡單類型的特殊性:文字、常量、編譯期求值
- ??struct?? 約束與 ?System.Enum?? 約束
一、核心行為:賦值即復制
值類型的變量直接包含類型實例,賦值時復制整個實例。
public struct MutablePoint
{
public int X;
public int Y;
?
public MutablePoint(int x, int y) => (X, Y) = (x, y);
public override string ToString() => $"({X}, {Y})";
}
?
var p1 = new MutablePoint(1, 2);
var p2 = p1; // 復制整個結(jié)構(gòu)體
p2.Y = 200; // 只影響 p2
?
Console.WriteLine(p1); // (1, 2) ? p1 不受影響
Console.WriteLine(p2); // (1, 200)
方法傳參也是復制:
static void MutateAndDisplay(MutablePoint p)
{
p.X = 100; // 改的是副本
Console.WriteLine(p); // (100, 200)
}
?
MutateAndDisplay(p2);
Console.WriteLine(p2); // (1, 200) ? 原值不受影響
劃重點: struct? 默認按值傳遞——方法內(nèi)部對參數(shù)的修改不會影響調(diào)用方的原始變量。這與 class 的行為正好相反。
二、重要陷阱:值類型包含引用類型成員
當結(jié)構(gòu)體內(nèi)部嵌套了引用類型(如 List<string>?),復制行為就變得有意思了——值類型實例被復制,但內(nèi)部的引用類型只復制了引用(地址) 。
public struct TaggedInteger
{
public int Number;
private List<string> tags;
?
public TaggedInteger(int n)
{
Number = n;
tags = new List<string>();
}
?
public void AddTag(string tag) => tags.Add(tag);
public override string ToString() => $"{Number} [{string.Join(", ", tags)}]";
}
?
var n1 = new TaggedInteger(0);
n1.AddTag("A");
Console.WriteLine(n1); // 0 [A]
?
var n2 = n1; // 復制結(jié)構(gòu)體
n2.Number = 7; // ? 只改 n2 的 Number(值類型成員)
n2.AddTag("B"); // ?? tags 是 List<string>,n1 和 n2 共享同一個 List
?
Console.WriteLine(n1); // 0 [A, B] ← n1 也被影響了!
Console.WriteLine(n2); // 7 [A, B]
- ?Number?(int,值類型)→ 復制時獨立
- ?tags?(List<string>?,引用類型)→ 復制時只復制引用,兩個結(jié)構(gòu)體實例共享同一個列表對象
| 操作 | ?n1.Number | ?n1.tags | ?n2.Number | ?n2.tags |
|---|---|---|---|---|
| 初始 | 0 | List["A"] | — | — |
| ?n2 = n1 | 0 | List["A"] | 0 | 同一個List["A"] |
| ?n2.Number = 7 | 0 | List["A"] | 7 | 同一個List["A"] |
| ?n2.AddTag("B") | 0 | List["A", "B"] | 7 | 同一個List["A", "B"] |
【提示】 官方明確建議:盡量使用不可變值類型。如果結(jié)構(gòu)體包含引用類型成員,一定要清楚這種"共享引用"的語義——這往往是 bug 的來源。
三、值類型的種類
C# 中的值類型有三種:
3.1 結(jié)構(gòu)類型(struct)
public struct Point { public int X; public int Y; }
3.2 枚舉類型(enum)
public enum Color { Red, Green, Blue }
3.3 聯(lián)合聲明(union)
定義一組封閉的事例類型,值可以表示。這是 .NET 6+ 引入的特性。
3.4 可為 null 的值類型(T?)
int? nullableInt = null; // Nullable<int> bool? nullableBool = null; // Nullable<bool>
?T?? 表示 T? 的所有值 + null?。不能為 null? 的值類型變量無法賦 null。
3.5 泛型約束
// struct 約束:類型參數(shù)必須是值類型(struct 或 enum)
public class MyClass<T> where T : struct { }
?
// System.Enum 約束:類型參數(shù)必須是枚舉類型
public class MyClass<T> where T : System.Enum { }
四、內(nèi)置值類型(簡單類型)
C# 提供以下內(nèi)置值類型,也稱為簡單類型:
| 類別 | 類型 |
|---|---|
| 整型 | ?byte?,sbyte?,short?,ushort?,int?,uint?,long?,ulong?,nint?,nuint |
| 浮點型 | ?float?,double?,decimal |
| 布爾 | ?bool |
| 字符 | ?char |
所有簡單類型都是結(jié)構(gòu)類型,但與其他結(jié)構(gòu)類型不同,它們允許一些額外操作:
| 操作 | 簡單類型 | 自定義結(jié)構(gòu)類型 |
|---|---|---|
| 文字常量 | ?'A'?、2001?、12.34m | ? |
| ??const??聲明 | ?const int Max = 100; | ? |
| 編譯期求值 | ? 常量表達式在編譯時求值 | ? |
// 簡單類型特有的操作
const int MaxItems = 100; // ? struct 是簡單類型
const decimal TaxRate = 0.05m; // ?
?
// 以下 ? 編譯錯誤
public struct Point { public int X; public int Y; }
// const Point Origin = new Point(); // 不能聲明結(jié)構(gòu)類型的常量
五、值元組
值元組(ValueTuple<T1, T2>?)是值類型,但不是簡單類型。
var point = (X: 10, Y: 20); // ValueTuple<int, int>
六、對比:值類型 vs 引用類型
| 維度 | 值類型 | 引用類型 |
|---|---|---|
| 變量內(nèi)容 | 數(shù)據(jù)本身 | 數(shù)據(jù)地址(引用) |
| 賦值行為 | 復制整個實例 | 復制引用(地址) |
| 默認傳參 | 按值傳遞(副本) | 按值傳遞引用(同上仍是副本) |
| ?null賦值 | ? 不可(除非T?) | ? |
| 存儲位置 | 棧/內(nèi)聯(lián) | 堆 |
| 繼承 | ?struct不能繼承 | ?class可以 |
| 性能 | 小數(shù)據(jù)快(無 GC 壓力) | 大數(shù)據(jù)好(引用傳遞) |
最后: 值類型的行為可以用一句話概括——值類型變量就是數(shù)據(jù)本身。賦值即復制、傳參即復制、包含引用類型成員時要小心"共享引用"。這些規(guī)則雖然簡單,但組合起來卻影響著日常編碼中的每一個細節(jié)。記住官方建議:優(yōu)先用不可變值類型,代碼會更可靠。
到此這篇關(guān)于C# 中值類型的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C# 值類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實現(xiàn)只運行單個實例應(yīng)用程序的方法(使用VB.Net的IsSingleInstance)
這篇文章主要介紹了C#實現(xiàn)只運行單個實例應(yīng)用程序的方法,本文使用的是VB.Net的IsSingleInstance方法實現(xiàn),優(yōu)于Mutex 和 Process 這兩種只運行單個應(yīng)用程序?qū)嵗姆椒?需要的朋友可以參考下2014-07-07
C#使用三層架構(gòu)開發(fā)Winform的詳細案例
這篇文章介紹了C#使用三層架構(gòu)開發(fā)Winform的詳細案例,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04
C#動態(tài)生成DropDownList執(zhí)行失敗原因分析
這篇文章主要介紹了C#動態(tài)生成DropDownList執(zhí)行失敗原因分析,以一個實例形式分析了C#動態(tài)生成DropDownList的相關(guān)注意要點與使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03
C#中實現(xiàn)輸入漢字獲取其拼音(漢字轉(zhuǎn)拼音)的2種方法
這篇文章主要介紹了C#中實現(xiàn)輸入漢字獲取其拼音(漢字轉(zhuǎn)拼音)的2種方法,本文分別給出了使用微軟語言包、手動編碼實現(xiàn)兩種實現(xiàn)方式,需要的朋友可以參考下2015-01-01

