C# 学习笔记一:变量、数据类型、控制流、数组、集合

老牛浏览 38评论 0发表于 更新于

目录

  1. C# 基础认知

  2. 变量与数据类型

  3. 控制流(分支与循环)

  4. 数组(Array)

  5. 集合(Collection)

  6. 可空引用类型

1. C# 基础认知

1.1 第一个程序

csharp
using System;  // 引入命名空间

class Program
{
    static void Main(string[] args)  // 程序入口
    {
        Console.WriteLine("Hello, C#!");  // 输出并换行
        Console.Write("不换行");           // 输出不换行
        Console.ReadKey();                // 等待按键
    }
}

1.2 using 的多种写法

写法

说明

适用版本

using System;

传统手动引入

所有版本

隐式全局 using

项目文件启用 <ImplicitUsings>enable</ImplicitUsings>

.NET 6+

using static System.Console;

引入静态成员,可省略类名

C# 6+

using alias = System.Collections.Generic.List<int>;

起别名

所有版本

csharp
// 隐式 using 自动引入的命名空间(.NET 6+ 控制台模板)
// System, System.Collections.Generic, System.Linq, System.Text, System.Threading.Tasks

2. 变量与数据类型

2.1 值类型(存储在栈上)

类型

关键字

字节

范围

示例

有符号8位

sbyte

1

-128 ~ 127

sbyte x = 100;

无符号8位

byte

1

0 ~ 255

byte b = 255;

有符号16位

short

2

-32,768 ~ 32,767

short s = 30000;

无符号16位

ushort

2

0 ~ 65,535

ushort u = 60,000;

有符号32位

int

4

-21亿 ~ 21亿

int age = 25; ⭐最常用

无符号32位

uint

4

0 ~ 42亿

uint ui = 4000000000;

有符号64位

long

8

-922亿亿 ~ 922亿亿

long l = 10000000000L;

无符号64位

ulong

8

0 ~ 1844亿亿

ulong ul = 10000000000UL;

单精度

float

4

±3.4×10³⁸(7位精度)

float f = 3.14f;

双精度

double

8

±1.7×10³⁰⁸(15位精度)

double d = 3.14; ⭐默认

高精度

decimal

16

±7.9×10²⁸(28位精度)

decimal m = 99.99m;

布尔值

bool

1

true/false

bool isReady = true;

字符

char

2

Unicode字符

char c = 'A';

2.2 引用类型(存储在堆上)

类型

关键字

示例

字符串

string

string name = "张三";

数组

int[]

int[] arr = {1, 2, 3};

对象

object

object obj = "任何类型";

2.3 引号的区别

引号类型

用于

示例

说明

双引号 " "

string

"Hello"

零个或多个字符

单引号 ' '

char

'A'

必须且只能一个字符

2.4 变量声明(多种写法)

csharp
// 方式1:显式声明(最常用)
int age = 25;
string name = "张三";

// 方式2:先声明后赋值
double height;
height = 175.5;

// 方式3:隐式类型(var)
var city = "北京";    // 推断为 string
var score = 95;       // 推断为 int
// ⚠️ var 不能用于:未初始化、null、类字段

// 方式4:常量
const double PI = 3.14159;

// 方式5:同时声明多个
int x = 1, y = 2, z = 3;

2.5 类型转换

csharp
// 隐式转换(自动,安全)
int small = 100;
long big = small;        // int → long
double d = small;        // int → double

// 显式转换(强制,可能丢失)
double pi = 3.99;
int integer = (int)pi;   // 结果为 3(截断,不是四舍五入)

// 安全转换方法
string text = "123";
int number = Convert.ToInt32(text);
int number2 = int.Parse(text);      // 可能抛异常
bool success = int.TryParse(text, out int result);  // 安全,不抛异常

// 数字转字符串
string str = number.ToString();
string str2 = $"{number}";

2.6 数字格式化

csharp
double value = 1234.5678;

// 标准格式(不区分大小写)
Console.WriteLine($"{value:f2}");   // 1234.57(2位小数)
Console.WriteLine($"{value:F4}");   // 1234.5678(4位小数)
Console.WriteLine($"{value:n2}");   // 1,234.57(千位分隔符)
Console.WriteLine($"{value:p1}");   // 123456.8%(百分比)
Console.WriteLine($"{value:e2}");   // 1.23e+003(科学计数法)
Console.WriteLine($"{value:c}");    // $1,234.57(货币,取决于区域)

// 十六进制(区分大小写)
int hex = 255;
Console.WriteLine($"{hex:x}");   // ff(小写)
Console.WriteLine($"{hex:X}");   // FF(大写)

2.7 数字类型选型决策树

plaintext
需要存储什么数据?
│
├─ 整数
│   ├─ < 255          → byte
│   ├─ < 32,767       → short
│   ├─ < 21亿         → int ✅
│   ├─ > 21亿         → long
│   └─ 只知道正数     → 考虑无符号(uint/ulong)
│
├─ 小数
│   ├─ 财务/货币      → decimal ✅
│   ├─ 科学/工程      → double ✅
│   └─ 游戏/图形/3D   → float
│
└─ 未知/混合          → double

3. 控制流(分支与循环)

3.1 if-else 语句

csharp
// 基本语法
if (条件1)
{
    // 条件1为true时执行
}
else if (条件2)
{
    // 条件1为false,条件2为true时执行
}
else
{
    // 所有条件都为false时执行
}

// 示例
int score = 85;
if (score >= 90)
    Console.WriteLine("优秀");  // 单条语句可省略{},但不推荐
else if (score >= 80)
    Console.WriteLine("良好");
else
    Console.WriteLine("继续加油");

3.2 switch 语句

csharp
// 传统 switch(C# 1.0)
string day = "周三";
switch (day)
{
    case "周一":
        Console.WriteLine("开始新的一周");
        break;  // 必须 break
    case "周三":
        Console.WriteLine("一周过半");
        break;
    case "周五":
        Console.WriteLine("周末快到了");
        break;
    default:
        Console.WriteLine("普通的一天");
        break;
}

// switch 表达式(C# 8.0+)
string result = day switch
{
    "周一" => "开始新的一周",
    "周三" => "一周过半",
    "周五" => "周末快到了",
    _ => "普通的一天"  // _ 相当于 default
};
Console.WriteLine(result);

// 模式匹配(C# 8.0+)
object obj = 42;
string type = obj switch
{
    int i when i > 0 => "正整数",
    int i when i < 0 => "负整数",
    string s => $"字符串:{s}",
    null => "空值",
    _ => "其他类型"
};

3.3 三元运算符(条件 ? : )

csharp
// 简单 if-else 的简写
int age = 18;
string status = (age >= 18) ? "成年人" : "未成年人";

// 嵌套三元(不推荐,可读性差)
string level = score >= 90 ? "A" : score >= 80 ? "B" : "C";

3.4 for 循环

csharp
// 基本语法
for (初始化; 条件; 迭代)
{
    // 循环体
}

// 示例:输出 1 到 5
for (int i = 1; i <= 5; i++)
{
    Console.WriteLine($"第 {i} 次循环");
}

// 多个变量
for (int i = 0, j = 10; i < j; i++, j--)
{
    Console.WriteLine($"i={i}, j={j}");
}

// 死循环
for (;;)
{
    // 需要 break 退出
}

3.5 while 循环

csharp
// while(先判断后执行)
int count = 0;
while (count < 5)
{
    Console.WriteLine($"计数: {count}");
    count++;
}

// do-while(至少执行一次)
int number;
do
{
    Console.Write("请输入正数:");
} while (!int.TryParse(Console.ReadLine(), out number) || number <= 0);
Console.WriteLine($"你输入了 {number}");

3.6 foreach 循环

csharp
// 遍历集合(最安全,只读)
string[] names = { "张三", "李四", "王五" };
foreach (string name in names)
{
    Console.WriteLine($"你好,{name}!");
}

// 获取索引(需要额外变量)
int index = 0;
foreach (var item in collection)
{
    Console.WriteLine($"[{index}] = {item}");
    index++;
}

3.7 跳转语句

csharp
// break:跳出循环
for (int i = 1; i <= 10; i++)
{
    if (i == 5) break;
    Console.Write(i + " ");  // 1 2 3 4
}

// continue:跳过本次循环
for (int i = 1; i <= 10; i++)
{
    if (i % 2 == 0) continue;
    Console.Write(i + " ");  // 1 3 5 7 9
}

// return:退出方法
static void Test()
{
    for (int i = 1; i <= 10; i++)
    {
        if (i == 5) return;  // 直接结束方法
        Console.Write(i + " ");  // 1 2 3 4
    }
    Console.WriteLine("不会执行");
}

// goto:跳转到标签(不推荐使用)
for (int i = 0; i < 10; i++)
{
    if (i == 5) goto End;
}
End:
Console.WriteLine("结束");

3.8 循环对比总结

循环类型

适用场景

是否知道次数

for

已知循环次数

✅ 知道

while

条件控制,可能一次都不执行

❌ 不知道

do-while

条件控制,至少执行一次

❌ 不知道

foreach

遍历集合/数组

✅ 知道(由集合决定)

4. 数组(Array)

4.1 数组初始化(5种写法演进)

csharp
// 方式1:最传统(C# 1.0)
string[] names1 = new string[3];
names1[0] = "张三";
names1[1] = "李四";
names1[2] = "王五";

// 方式2:声明时分配(指定大小)
string[] names2 = new string[3] { "张三", "李四", "王五" };

// 方式3:省略大小(编译器推断)
string[] names3 = new string[] { "张三", "李四", "王五" };

// 方式4:数组初始化器(C# 3.0+)
string[] names4 = { "张三", "李四", "王五" };  // ⭐ 最常见

// 方式5:集合表达式(C# 12.0+ / .NET 8+)
string[] names5 = ["张三", "李四", "王五"];   // ⭐ 最新写法

// 空数组
string[] empty1 = new string[0];
string[] empty2 = Array.Empty<string>();
string[] empty3 = { };
string[] empty4 = [];  // C# 12+ 最简洁

4.2 多维数组

csharp
// 矩形数组(二维)
int[,] matrix = new int[3, 4];  // 3行4列
int[,] matrix2 = { {1, 2}, {3, 4}, {5, 6} };
Console.WriteLine(matrix2[0, 1]);  // 2

// 锯齿数组(数组的数组)
int[][] jagged = new int[3][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
jagged[2] = new int[] { 6 };
Console.WriteLine(jagged[1][2]);  // 5

4.3 数组常用操作

csharp
int[] arr = { 5, 2, 8, 1, 9 };

// 长度
int len = arr.Length;

// 排序
Array.Sort(arr);  // { 1, 2, 5, 8, 9 }

// 反转
Array.Reverse(arr);  // { 9, 8, 5, 2, 1 }

// 查找
int index = Array.IndexOf(arr, 5);  // 2
int index2 = Array.LastIndexOf(arr, 5);

// 复制
int[] copy = new int[3];
Array.Copy(arr, copy, 3);

// 清空
Array.Clear(arr, 0, arr.Length);  // 全部设为默认值(0/null)

4.4 数组 vs List 对比

特性

数组 T[]

List<T>

大小

固定,不可变

动态,自动扩容

性能

更快

稍慢(有额外开销)

添加元素

不支持

Add(), Insert()

删除元素

不支持

Remove(), RemoveAt()

使用场景

固定数据

频繁增删改查

5. 集合(Collection)

5.1 List<T>(动态数组)

csharp
using System.Collections.Generic;

// 创建方式
List<string> names = new List<string>();
List<int> scores = new List<int> { 90, 85, 78, 92 };  // 初始化
var list = new List<string>();  // var 推断
List<string> list2 = [];  // C# 12+ 集合表达式

// 常用操作
names.Add("张三");                    // 添加
names.Insert(1, "赵六");              // 插入
names.Remove("李四");                 // 删除
names.RemoveAt(0);                   // 按索引删除
names.RemoveAll(x => x.StartsWith("张")); // 条件删除
int count = names.Count;             // 个数
bool exists = names.Contains("王五"); // 是否存在
int idx = names.IndexOf("李四");      // 查找索引(-1表示不存在)
names.Sort();                        // 排序
names.Reverse();                     // 反转
names.Clear();                       // 清空

// 批量操作
names.AddRange(new[] { "赵六", "孙七" });  // 批量添加
List<string> subList = names.GetRange(0, 2); // 获取子列表

5.2 Dictionary<TKey, TValue>(键值对)

csharp
// 创建方式
Dictionary<int, string> students = new Dictionary<int, string>();
Dictionary<string, int> scores = new()
{
    { "张三", 95 },
    { "李四", 87 }
};
var dict = new Dictionary<string, string>();

// 常用操作
students.Add(1001, "张三");          // 添加
students[1002] = "李四";              // 添加或覆盖
string name = students[1001];        // 访问(可能抛异常)

// 安全访问
if (students.ContainsKey(1003))
{
    Console.WriteLine(students[1003]);
}

// TryGetValue(最佳实践)
if (students.TryGetValue(1004, out string? foundName))
{
    Console.WriteLine($"找到:{foundName}");
}
else
{
    Console.WriteLine("学号不存在");
}

// 遍历
foreach (KeyValuePair<int, string> kvp in students)
{
    Console.WriteLine($"键:{kvp.Key},值:{kvp.Value}");
}

// 只遍历键或值
foreach (int id in students.Keys) { }
foreach (string studentName in students.Values) { }

// 删除
students.Remove(1001);
students.Clear();

5.3 HashSet<T>(唯一值集合)

csharp
HashSet<string> uniqueNames = new HashSet<string>();
uniqueNames.Add("张三");
uniqueNames.Add("李四");
bool added = uniqueNames.Add("张三");  // false(已存在)

// 初始化
HashSet<int> set = new HashSet<int> { 1, 2, 3, 4, 5 };

// 集合操作
HashSet<int> set1 = new HashSet<int> { 1, 2, 3 };
HashSet<int> set2 = new HashSet<int> { 3, 4, 5 };

set1.IntersectWith(set2);  // 交集:{3}
set1.UnionWith(set2);      // 并集:{1,2,3,4,5}
set1.ExceptWith(set2);     // 差集:{1,2}
set1.SymmetricExceptWith(set2); // 对称差:{1,2,4,5}

bool isSuperset = set1.IsSupersetOf(set2);
bool isSubset = set1.IsSubsetOf(set2);

5.4 Stack<T>(栈 - 后进先出 LIFO)

csharp
Stack<string> stack = new Stack<string>();
stack.Push("操作1");   // 压入
stack.Push("操作2");
stack.Push("操作3");

string last = stack.Pop();    // "操作3"(弹出)
string top = stack.Peek();    // "操作2"(只看不弹)
bool isEmpty = stack.Count == 0;

5.5 Queue<T>(队列 - 先进先出 FIFO)

csharp
Queue<string> queue = new Queue<string>();
queue.Enqueue("任务1");  // 入队
queue.Enqueue("任务2");
queue.Enqueue("任务3");

string first = queue.Dequeue();  // "任务1"(出队)
string next = queue.Peek();      // "任务2"(只看不出)

5.6 集合对比总结

集合

特点

有序

重复

访问方式

适用场景

List<T>

动态数组

索引 [i]

存储列表数据

Dictionary<TKey,TValue>

键值对

键唯一

[key]

通过ID快速查找

HashSet<T>

唯一值

Contains

去重、集合运算

Stack<T>

后进先出

Push/Pop

撤销、递归

Queue<T>

先进先出

Enqueue/Dequeue

任务队列

6. 可空引用类型(Nullable Reference Types)

6.1 核心概念

C# 8.0+ 引入,引用类型分为两种:

类型

声明

能否为null

说明

不可为空

string name

保证永远有值

可为空

string? name

可能为null,需要检查

6.2 处理可空值的方法

csharp
// 1. 声明为可空类型
if (dict.TryGetValue(1004, out string? value))
{
    Console.WriteLine(value);
}

// 2. var 自动推断为可空
if (dict.TryGetValue(1004, out var value))
{
    Console.WriteLine(value);
}

// 3. 空值合并运算符 ??
string name = GetName() ?? "默认用户";

// 4. 空值合并赋值 ??=
string? input = null;
input ??= "默认值";  // input 现在为 "默认值"

// 5. 空值条件运算符 ?.
string? user = null;
int length = user?.Length ?? 0;  // 避免 NullReferenceException

// 6. 空值条件 + 索引
string? first = users?.FirstOrDefault()?.Name;

// 7. 非空断言运算符 !(告诉编译器"我保证不为null",谨慎使用)
string name = GetName()!;

6.3 可空值类型(值类型的可空版本)

csharp
// 值类型默认不可为null
int x = null;  // ❌ 编译错误

// 使用 Nullable<T> 或 T? 使其可为null
int? y = null;      // ✅ 可为null
bool? flag = null;  // ✅ 可为null

// 访问可空值类型
int? age = null;
if (age.HasValue)
{
    Console.WriteLine(age.Value);
}
else
{
    Console.WriteLine("年龄未知");
}

// 使用 GetValueOrDefault
int actualAge = age.GetValueOrDefault();  // 如果为null,返回默认值0
int actualAge2 = age ?? 18;  // 如果为null,使用18

6.4 项目配置

xml
<!-- .csproj 文件中 -->
<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <Nullable>enable</Nullable>  <!-- 开启可空检查 -->
</PropertyGroup>

📝 快速参考卡片

常用类型快捷写法

csharp
// 数组初始化
int[] arr = { 1, 2, 3 };           // 传统
int[] arr = [1, 2, 3];             // C# 12+

// List 初始化
List<int> list = new List<int> { 1, 2, 3 };
List<int> list = [1, 2, 3];        // C# 12+

// Dictionary 初始化
var dict = new Dictionary<string, int>
{
    { "a", 1 },
    { "b", 2 }
};
// C# 12+ 暂不支持字典集合表达式

// 空集合
int[] empty = [];                  // 数组空
List<int> empty = [];              // List空
string[] empty = Array.Empty<string>();  // 无分配空数组

控制流速查

csharp
if (条件) { } else if { } else { }
switch (值) { case 常量: break; default: break; }
条件 ? 真值 : 假值
for (初始化; 条件; 迭代) { }
while (条件) { }
do { } while (条件)
foreach (var item in 集合) { }
break / continue / return
点赞
收藏
暂无评论,快来发表评论吧~