(C#) 精简 C# 入门(四)

最近在做一些需要用到 C# 开发的项目,许久未碰有些生疏,因此决定把语言的基础内容先都快速过一遍。为方便查阅,挑选最精简的部分整理于该博客。

【说明】

  1. 本系列的目标是整理出十个以内的博客(传送门),适合快速入门。目前更新到:精简 C# 入门(五)
  2. 本系列不适用于完全的编程初学者(未接触任何计算机语言),这一类读者建议仔细学习【参考资料】中的视频资源

【参考资料】
1.b站:【01_C#入门到精通】新手强烈推荐:C#开发课程,一整套课程

#1 类的引用

引用系统类:
系统类一般都位于名字类似为 System.XXX 的命名空间,因此只需直接在代码开头添加:

using System.XXX;

引用自定义的类:
例如想要在 PlaneChess 项目中使用 ConsoleApp2 中定义的 Pet 类(下图红框):

  1. 右键单击 引用,选择 添加引用
    在这里插入图片描述
  2. 在弹窗中勾选 ConsoleApp2,点击确定
    在这里插入图片描述
  3. 使用 using 添加 using ConsoleApp2,然后就能调用其中的 Pet 类了。
    注意!这个该类必须是由 public 修饰的,即允许外界访问

#2 字符串 string

作者在 精简 C# 入门(一)已经对各类基础数据类型进行了简短的概括,包括字符串。但由于字符串存在典型性与特殊性,因此在这里补充对其更细致的介绍。

2.1 字符串的不可变性 & StringBuilder 的使用

字符串为引用类型,其值储存在堆,地址储存在栈
这一块的内容详见 精简 C# 入门(一)Section #5

值相同的字符串指向同一个堆地址
如下图,字符串 s1, s2 均指向同一个 “张三”,不存在第二个 “张三”
在这里插入图片描述

字符串的不可变性
当给字符串重新赋值时,原初值并没有销毁,而是在堆中重新开辟一块区域储存。如下图中字符串 s 赋新值 “孙权” 后,其初值 “张三” 并未在堆中被销毁。
在这里插入图片描述

不同于栈空间垃圾内存的立即销毁,像这样未被销毁的堆空间垃圾,只有当程序结束时才会被处理。因此为了防止程序运行时内存占用过高,要避免大量的对字符串的赋值操作

使用 StringBuilder 避免对字符串的操作占用过量内存
示例:将 1-100 的整数串成一个字符串

// 直接用 string:占用内存且耗时
string s = "";
for (int i = 0: i < 100; i++)
{
	s += i;
}

// 使用 StringBuilder:不占内存且高效
StringBuilder sb = new StringBuilder();
for (int i = 0: i < 100; i++)
{
	sb.Append(i);
}
string s = sb.ToString();

2.2 修改字符串

字符串相当于一个 char 类型的只读数组
我们可以使用 字符串名[index] 的方式来访问该位置的字符,但无法修改。

使用 char[]string 的相互转换修改字符串中的字符
虽然字符串可以看作只读 char[],但是仍然可以通过一些列操作来修改其某个位置的字符,实现 “曲线救国”。示例:

string str = "Hello World!"
// 首先将其转化为 char[]
char[] chs = str.ToCharArray();
// 相当于删去 "Hello" 末尾的 "o"
chs[4] = "";
// 再转回字符串
str = new string(chs);

>>>
"Hell World!"

2.3 字符串的相关方法

以下代码中 [] 里的内容表示该方法的返回值类型:

[double] str.Length;                        // 长度
[string] str.ToUpper();                     // 转成大写
[string] str.ToLower();                     // 转成小写
[bool] str.Equals(str1);                    // 判断两个字符串是否相同
	// 该函数还有一个枚举类型的可选参数,具体作用百度
	str.Equals(str1, StringComparison.XXX)
		
[bool] str.Contains(substr);                // 判断字符串中是否包含 substr
[bool] str.StartsWith(substr);              // 判断字符串是否以 substr 开头
[bool] str.EndsWith(substr);                // 判断字符串是否以 substr 结尾
[bool] string.IsNullorEmpty(str);           // 判断字符串是否为 null or ""

[int] str.IndexOf(substr);                  // 找 substr 第一次出现的 index
	str.IndexOf(substr, startIndex)         // 从 startIndex 开始找
[int] str.LastIndexOf(substr);              // 找 substr 最后一次出现的 index

[string] str.Trim();                        // 去掉字符串开头与结尾的空格
[string] str.TrimStart();                   // 去开头空格
[string] str.TrimEnd();                     // 去结尾空格

[string] str.Replace(substr1, substr1);     // 将子串 substr1 替换为 substr2
[string] str.Substring(startIndex, length); // 从 startIndex 位置截取长度为 length 的子串

应用1:使用 LastIndexOf, Substring 提取地址中文件名

string path = @"C:\file1\file2\1.txt":
int index = path.LastIndexOf("\\"); // "\\" 表示 "\"
string fileName = path.Substring(index+1);

>>>
"1.txt"

分割字符串

[string[]] str.Split(chs, StringSplitOptions.None/RemoveEmptyEntries)
  1. chschar[] 类型,储存作为分割依据的字符
  2. StringSplitOptions.None/RemoveEmptyEntries 是一个枚举类型的可选参数
    None 表示不删除分割后的空值 ""
    RemoveEmptyEntries 表示删除

示例:

string str = "a b  + c";
char[] chs = { ' ', '+' };

string[] splits = str.Split(chs, StringSplitOptions.RemoveEmptyEntries);
>>>
{ "a", "b", "c" }


string[] splits = str.Split(chs, StringSplitOptions.None);
>>>
{ "a", "b", "", "", "", "c" }

拼接字符串

[string] string.Split(connection, str);

示例:

string[] strs = { "a", "b", "c" };
string strJoint = string.Join(" | ", strs);
>>>
"a | b | c"

#3 文件操作之 File

File 类是一个静态的系统类,这里介绍一些其中的方法:

读取文件的每一行

using System.IO;
using System.Text;

[string[]] File.ReadAllLines(path, Encoding.XXX);

path 为 string 类型的路径,
Encoding.XXX 为解码方式,常见有 Encoding.Default, Encoding.UTF8 等

#4 继承

继承主要是类的继承,通过子类继承父类的形式,使得子类能够沿用父类当中的字段、属性与方法(只能继承 public 的),从而降低代码冗余。

示例,子类 Cat 继承父类 Animal

public class Animal
{
	private int _age;
	public int Age { get => _age; set => _age = value; }
}

public class Cat: Animal
{
	// 代码块
}

继承具有传递性,即子类的子类能够继承父类中的字段、属性与方法。

子类不继承父类的构造函数。但是可以通过在子类的构造函数前添加 :base([参数列表]) 来实现构造函数的继承,示例:

public class Animal
{
	public Animal(int age)
	{
		this.Age = age;
	}

	private int _age;
	public int Age { get => _age; set => _age = value; }
}

public class Cat: Animal
{
	public Cat(int age, string name)
		: base(age)
	{
		this.Name = name;
	}
	
	private string _name;
	public string Name { get => _name; set => _name = value; }
}

如果在子类中需要写一个与父类中的同名的成员,建议为其添加一个关键字 new(不加也不会报错,但是加了就看的比较清楚),示例:

public class Animal
{
	public void Shout()
	{
		Console.WriteLine("发出了叫声");
	}
}

public class Cat: Animal
{
	public new void Shout()
	{
		Console.WriteLine("喵!");
	}
}

#5 里式转换

核心含义:

  1. 子类可以赋值给父类
  2. 如果父类对象中装的是子类对象,那么可已将这个父类强转为子类对象

子类可以赋值给父类
依旧以上个代码片段中的 Animal, Cat 类为例:

Cat cat = new Cat();
Animal animal1 = cat;
Animal animal2 = new Cat();

作用:当一个地方需要某类的对象时,可以使用其子类的对象替代

如果父类对象中装的是子类对象,那么可已将这个父类强转为子类对象
示例:

Aniaml animal = new Cat(); // 父类对象中装的是子类对象
Cat cat = (Cat)animal;     // 强转

#6 protected 访问修饰符

private: 仅限于类的内部访问
public: 不限访问
protected: 仅限于类内部及其子类访问

#7 ArrayList 泛型集合

注意:ArrayList 由于在读写的过程中存在类型转换(装箱/拆箱),导致其读写速度较为缓慢,因此一般更多地会 使用 List<> 代替 ArrayList,详见 Section 8

using System.Collections;

ArrayList list = new ArrayList();

集合的概念类似于数组,但是不同于数组的长度固定、元素类型单一,集合没有这些限制。集合也有缺陷,由于任何添加进集合的元素都会被自动转换为 object 类型,因此在之后调用这些元素的时候,需要使用强制类型转换,示例:

list.Add(1);
list.Add(2);

int sum = (int)list[0] + (int)list[1];

类方法:以下代码中 obj 表示任意类型的元素

list.Count;                   // 查看长度
list.Capacity;                // 查看集合容量
	// 数组容量只能等于 0, 4, 8, 16, 32... 依据集合长度而发生变化
	// 例如 count=4 时 capacity=4, cout=5 时 capacity=8

list.Add(obj);                // 添加元素
list.AddRange(数组、集合);      // 依次添加数组或集合中的每个元素
list.Clear();                 // 清空集合
list.Remove(obj);             // 根据值来删除元素
list.RemoveAt(index);         // 根据 index 删除元素
list.RemoveRange(start, end); // 移除一定范围的元素
list.Reverse();               // 反转
list.Insert(index, obj);      // 插入元素
list.InsertRange(index, 数组、集合);

[bool] list.Contain(obj);     // 判断是否包含  

#8 List<> 泛型集合

创建对象

List<数据类型> 对象名 = new List<数据类型>();

List<> 泛型集合的大部分类方法同 ArrayList,详见 Section 7。除此以外,泛型集合也有一些独有的类方法:

List<int> list = new List<int>();

[int[]] list.ToArray(); // 将 List<> 转换为数组
	// 当然也可以将数组转换为 List<>
	[List<int>] array.ToList();

#9 HashTable 键值对集合

注意:HashTable 由于在读写的过程中存在类型转换(装箱/拆箱),导致其读写速度较为缓慢,因此一般更多地会 使用 Dictionary 代替 HashTable,详见 Section 10

类似 Python 中的字典,键必须唯一,值可以重复

using System.Collections;

HashTable ht = new HashTable();

类方法

ht.Count;         // 长度

ht.Add(,);   // 添加方法 1
ht[] =;      // 添加方法 2
 // 这里的键、值可以是任意类型的元素,类似于 Python 中的 dict[key] = value;
ht.Clear();      // 清空
ht.Remove();   // 根据键来移除键值对

[value] ht[key];        // 根据键找值
[collection] ht.Keys;   // 返回所有键
[collection] ht.Values; // 返回所有值
	// 读取键、值时,无法使用 ht.Keys[index] 这样的形式
	// 但可以使用 foreach (var item in ht.Keys) {  } 来读取

[bool] ht.ContainsKey();   // 判断是否包含某个键
[bool] ht.COntainsValue(); // 判断是否包含某个值

#10 Dictionary 键值对集合

创建对象

Dictionary<键类型, 值类型> dict = new Dictionary<键类型, 值类型>();

Dictionary 键值对集合的大部分类方法同 HashTable,详见 Section 9。

读取 Dictionary 中的键值对的两种方法

Dictionary<int, string> dict = new Dictionary<int, string>();

// 方法 1
foreach (var key in dict.Keys)
{
	Console.WriteLine("{0}, {1}", key, dict[key]);
}

// 方法 2
foreach (KeyValuePair<int, string> kv in dict)
{
	Console.WriteLine("{0}, {1}", kv.Key, kv.Value);
}
  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江湖留名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值