在 C# 中,基本值类型(如 int
、float
、char
等)的字节数是固定的,与操作系统位数(32位或64位)无关,因为它们是由 .NET 规范 定义的。
但是,string(字符串)是引用类型,内存占用是不固定的,取决于字符串的长度和编码方式。string在内存中的大小由以下部分组成:
char
占用 2 字节(UTF-16 编码)\0
,2 字节)"Hello"
(5个字符)
8 + 4 + 4 + (5×2) + 2 = 28 字节
16 + 8 + 4 + (5×2) + 2 = 40 字节
(1)整数类型:
类型 | 字节数 | 位数 | 范围 |
sbyte | 1 | 8 | -128 到 127 |
byte | 1 | 8 | 0 到 255 |
short | 2 | 16 | -32,768 到 32,767 |
ushort | 2 | 16 | 0 到 65,535 |
int | 4 | 32 | -2,147,483,648 到 2,147,483,647 |
uint | 4 | 32 | 0 到 4,294,967,295 |
long | 8 | 64 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
ulong | 8 | 64 | 0 到 18,446,744,073,709,551,615 |
(2)浮点类型:
类型 | 字节数 | 位数 | 范围 |
float | 4 | 32 | ±1.5×10⁻⁴⁵ 到 ±3.4×10³⁸,7位精度 |
double | 8 | 64 | ±5.0×10⁻³²⁴ 到 ±1.7×10³⁰⁸,15-16位精度 |
decimal | 16 | 128 | ±1.0×10⁻²⁸ 到 ±7.9×10²⁸,28-29位精度 |
(3)其他类型:
类型 | 字节数 | 位数 | 范围 |
bool | 1 | 8 | true/false |
char | 2 | 16 | — |
string | — | — | — |
(1)隐式转换是编译器自动执行的类型转换,不需要特殊语法,且不会丢失数据。隐式转换通常需要满足从较小整数类型到较大整数类型(如 int
到 long
):
int i = 123;
long l = i; // 隐式转换为long
float f = l; // 隐式转换为float
(2)显式转换需要使用强制转换运算符,可能丢失数据或引发异常:
double d = 123.456;
int i = (int)d; // 显式转换为int,小数部分被截断
(3)使用 Convert 类,System.Convert 类提供了一系列静态方法用于类型转换:
string str = "123";
int i = Convert.ToInt32(str);
double d = Convert.ToDouble("123.45");
(4)Parse 和 TryParse 方法,基本类型都提供了 Parse 和 TryParse 方法:
// Parse 方法 - 转换失败会抛出异常
int i = int.Parse("123");
// TryParse 方法 - 转换失败不会抛出异常
bool success = int.TryParse("123", out int result);
转义字符是C#中用于表示特殊字符序列的字符组合,以反斜杠(\
)开头。它们允许你在字符串中插入无法直接输入或具有特殊含义的字符:
\' | 单引号 | \0 | 空字符(null) | \t | 水平制表符 |
\" | 双引号 | \n | 换行 | \v | 垂直制表符 |
\\ |
反斜杠 | \r | 回车 | \f | 换页 |
string path = "C:\\Users\\John\\Documents"; // 使用转义字符表示路径
string quote = "He said, \"Hello World!\""; // 在字符串中包含双引号
string newLine = "First line\nSecond line"; // 换行
当字符串中包含大量反斜杠或转义字符时,可以使用@前缀创建逐字字符串字面量,这样反斜杠就不会被解释为转义字符,这样可以更简洁的输出 "\" 等其他转义字符 :
string path = @"C:\Users\John\Documents"; // 不需要转义反斜杠
string multiLine = @"第一行
第二行
第三行"; // 直接包含换行
string quote = @"He said, ""Hello World!"""; // 在逐字字符串中,要表示双引号需要使用两个双引号:
(1)string.Format方法
允许使用占位符 {0}
, {1}
, {2}
... 来插入变量,并可以指定格式。
string name = "Alice";
int age = 25;
double salary = 1234.567;
string formatted = string.Format("Name: {0}, Age: {1}, Salary: {2}", name, age, salary);
Console.WriteLine(formatted);
// 可以在占位符 {n} 后面加 :格式 来控制输出样式
double salary = 1234.567;
string formatted = string.Format("Salary: {0:C2}", salary); // C2 = 货币格式,2位小数
Console.WriteLine(formatted);
常用格式说明符:
格式 | 说明 | 示例 |
{0:C} | 货币格式 | 1234.567 → $1,234.57 |
{0:N2} | 数字格式(2位小数) | 1234.567 → 1,234.57 |
{0:P} | 百分比格式 | 0.123 → 12.30% |
{0:D4} | 整数补零(仅限整数) | 25 → 0025 |
{0:yyyy-MM-dd} | 日期格式 | DateTime.Now → 2024-06-20 |
(2)插值字符串($""
)是一种更简洁的格式化方式,直接在字符串中嵌入变量和表达式。
string name = "Bob";
int age = 30;
Console.WriteLine($"Name: {name}, Age: {age}");
// 可以在变量后加 :格式
double salary = 1234.567;
Console.WriteLine($"Salary: {salary:C2}"); // 货币格式,2位小数
(3)Console.WriteLine可以直接使用 string.Format
风格的格式化。
string name = "Charlie";
int score = 95;
Console.WriteLine("Player: {0}, Score: {1:D3}", name, score); // D3 = 3位数字,补零
(4)ToString()方法,所有类型都有 ToString()
方法,可以传入格式字符串。
DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("yyyy-MM-dd HH:mm:ss")); // 自定义日期格式
if (condition1)
{
// 条件1为 true 时执行的代码
}
else if (condition2)
{
// 条件2为 true 时执行的代码
}
else
{
// 所有条件都为 false 时执行的代码
}
switch (expression)
{
case value1:
// 代码块
break;
case value2:
// 代码块
break;
case value3:
case value4:
// 代码块
break;
default:
// 默认代码块
break;
}
简洁的条件表达式
int number = 10;
string result = number > 0 ? "正数" : "非正数";
Console.WriteLine(result); // 输出: 正数
明确知道循环次数时使用,包含初始化、条件检查和迭代部分
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"当前值: {i}");
}
用于遍历集合或数组,不需要维护计数器,不能修改集合中的元素(只读访问)
string[] colors = { "红", "绿", "蓝" };
foreach (string color in colors)
{
Console.WriteLine(color);
}
条件为真时执行循环,循环次数不确定时使用,可能一次都不执行(条件初始为假)
int count = 3;
while (count > 0)
{
Console.WriteLine($"剩余次数: {count}");
count--;
}
至少执行一次循环体,执行后检查条件,适用于需要至少执行一次的场景
int number;
do
{
Console.Write("请输入一个正数: ");
} while (!int.TryParse(Console.ReadLine(), out number) || number <= 0);
break:立即终止整个循环,并跳出循环体,继续执行循环之后的代码。
continue:跳过当前迭代的剩余代码,直接进入循环的下一次迭代(不终止整个循环)。
// 声明一个整数数组(未初始化)
int[] numbers;
// 声明一个字符串数组
string[] names;
// 方式1:声明时指定大小
int[] numbers1 = new int[5]; // 5个元素的数组,默认值为0
// 方式2:声明时初始化元素
int[] numbers2 = new int[] { 1, 2, 3, 4, 5 };
// 方式3:简化语法
int[] numbers3 = { 1, 2, 3, 4, 5 };
// 方式4:先声明后初始化
int[] numbers4;
numbers4 = new int[] { 1, 2, 3, 4, 5 };
int[] numbers = { 10, 20, 30, 40, 50 };
// 访问第一个元素
int first = numbers[0]; // 10
// 修改第三个元素
numbers[2] = 35; // 现在数组变为 {10, 20, 35, 40, 50}
// 获取数组长度
int length = numbers.Length; // 5
// 遍历数组方式1:
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
// 遍历数组方式2:
foreach (int i in numbers)
{
Console.WriteLine(i);
}
string str1 = "Hello";
string str2 = "HelloWorld";
int length = str1.Length; // 获取长度 → 5
bool isEmpty = string.IsNullOrEmpty(str1); // 检查是否为空或null
int result1 = string.Compare(str1, str2); // 区分大小写比较
int result2 = string.Compare(str1, str2, StringComparison.OrdinalIgnoreCase); // 不区分大小写
string lower = str2.ToLower(); // 转小写 → "helloworld"
string upper = str2.ToUpper(); // 转大写 → "HELLOWORLD"
int index1 = str2.IndexOf('o'); // 查找字符位置 → 4
int index2 = str2.LastIndexOf('o'); // 从后向前查找 → 6
int index3 = str2.IndexOf("World"); // 查找子串位置 → 5
string replaced = str2.Replace("World", "C#"); // 替换 → "HelloC#"
string removed1 = str2.Remove(5); // 删除位置5后的字符(包括5) → "Hello"
string removed2 = str2.Remove(5, 3); // 从位置5开始删除3个字符(包括5) → "Hellold"
string trimmed1 = str2.Trim(); // 去除两端空白
string trimmed2 = str2.TrimStart(); // 仅去除开头空白
string trimmed3 = str2.TrimEnd(); // 仅去除结尾空白
string[] sp = str2.Split('o'); // 以'o'进行分割得到 → ["Hell", "W", "rld"]
方法是 C# 编程中的基本构建块,用于封装可重用的代码逻辑。
public static int Add(int a, int b)
{
return a + b;
}
public
:无访问限制private
:仅当前类可访问(默认)protected
:当前类及派生类可访问internal
:同一程序集可访问protected internal
:同一程序集或派生类可访问值参数:
void ModifyValue(int x)
{
x = 10; // 只修改副本
Console.WriteLine(x); // 输出 10
}
int num = 5;
ModifyValue(num);
Console.WriteLine(num); // 输出 5 (原始值未改变)
引用参数:
void ModifyRef(ref int x)
{
x = 10; // 修改原始变量
}
int num = 5;
ModifyRef(ref num);
Console.WriteLine(num); // 输出 10 (原始值已改变)
参数数组:
int Sum(params int[] numbers)
{
return numbers.Sum();
}
var total = Sum(1, 2, 3, 4, 5); // 输出 15
函数重载(Function Overloading)是C#中一项重要的特性,它允许在同一个作用域内定义多个同名函数,但这些函数的参数列表必须不同。规则如下:
public class Calculator
{
// 版本1:两个整数相加
public int Add(int a, int b)
{
return a + b;
}
// 版本2:三个整数相加(参数数量不同)
public int Add(int a, int b, int c)
{
return a + b + c;
}
// 版本3:两个双精度浮点数相加(参数类型不同)
public double Add(double a, double b)
{
return a + b;
}
// 版本4:整数和双精度浮点数相加(参数顺序不同)
public double Add(int a, double b)
{
return a + b;
}
// 版本5:双精度浮点数和整数相加(参数顺序不同)
public double Add(double a, int b)
{
return a + b;
}
// 错误示例:仅返回类型不同,不能构成重载
// public float Add(int a, int b) { return a + b; }
}
递归是编程中一种重要的技术,它指的是一个方法直接或间接调用自身的过程。在C#中,递归可以优雅地解决许多问题,特别是那些可以分解为相同子问题的情况。
递归由两个主要部分组成:
斐波那契数列:
static int again(int n)
{
// 基准条件
if (n == 0)
{
return 2;
}
if (n == 1)
{
return 3;
}
// 递归条件
return again(n - 1) + again(n - 2);
}
static void Main(string[] args)
{
Console.WriteLine(again(40));
}
求阶乘:
static int again(int n)
{
if ( n==1)
{
return 1;
}
return again(n - 1) * n;
}
static void Main(string[] args)
{
Console.WriteLine(again(10));
}
在 C# 中,常量是指在程序运行期间其值不会改变的标识符。常量提供了一种使代码更易读、更易维护的方式,同时也提高了程序的性能。
public class MyClass
{
// const 数据类型 常量名 = 值;
public const double PI = 3.14159;
}
常量的特点:
枚举(Enum)是C#中一种特殊的值类型,它允许你定义一组命名的常量值。枚举使代码更易读、更易维护,因为它用有意义的名称替代了数字常量。
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
枚举的特点:
int
,但可以指定其他整数类型(byte, sbyte, short, ushort, int, uint, long, ulong)结构体(struct)是C#中的一种值类型,用于封装小型相关变量的集合。结构体类似于类,但有一些重要区别。
public struct Point
{
public int X;
public int Y;
// 自定义构造函数
public Point(int x, int y)
{
X = x;
Y = y;
}
// 方法
public void Move(int deltaX, int deltaY)
{
X += deltaX;
Y += deltaY;
}
}
结构体的特点:
委托(Delegate)是 C# 中一种强大的功能,它本质上是一种类型安全的函数指针,允许将方法作为参数传递或存储为变量。委托是 .NET 中事件和回调机制的基础。
// 声明一个委托类型
public delegate void MyDelegate(string message);
// 定义与委托匹配的方法
public static void ShowMessage(string msg)
{
Console.WriteLine(msg);
}
// 使用委托
MyDelegate del = new MyDelegate(ShowMessage);
del("Hello, Delegate!");
委托的特点: