C#精通
本文章主要是对于学习C#基础难点进行学习以及与java语言的不同点,详细学习可见官网:https://dotnet.microsoft.com/en-us/learn
文章目录
VS
- 安装VS,目录:解决方案>项目>类 可在方案中创建多个项目。
VS基本设置
- 生成->生成解决方案 可排查错误
- 工具->选项 可设置字体,行号
- vs默认启动第一项目,右击解决方案->属性可自选
- 快捷键
ctrl+k+d:快速对齐 ctrl+j:提示 shift+alt+f10:生成解决方案 ctrl+alt+x:打开工具箱
- 折叠代码
C#是什么
C#(发音为 “C Sharp”)是一种现代、面向对象的、类型安全的编程语言,由微软开发,首次发布于2000年。C#的设计者是Anders Hejlsberg,他也是Turbo Pascal和Delphi的创造者。C#结合了C++的强大特性和Visual Basic的易用性,旨在提供一种新的编程语言,以适应.NET框架的需要。
语法和Java很类似
C#程序
控制台输出
每个语言都有控制台输出,如java中的println
> 逐字字符串文本将保留所有空格和字符,而无需转义反斜杠。
要创建逐字字符串,请在文本字符串的前面使用 @ 指令。
```java
C# 不换行输出Console.Write()
换行输出Console.WriteLine()
如需原封不动输出
Console.Write(@"hsfdsj
dfjkslfjdsklf kdfj \\\ n ");
```
- Console.ReadKey();等待用户按下任意键 参数为true不显示控制台
- Console.ReadLine();接受用户输入 相当于java new Scanner(System…).next()
- 控制台前景色:Console.ForegroundColor = ConsoleColor.Red;
- Console.Clear():清空控制台
变量内插
若要将两个字符串内插在一起,请创建一个文本字符串,并在字符串前面加上 $ 符号。 文本字符串应包含至少一组大括号 {},且你会在这些字符内使用变量的名称。
```java
public static void test2()
{
var firstName = "张三";
String a = $"hello {firstName}";
Console.Write($"{a}");
}
```
`@和$可联合使用`
```java
public static void test2()
{
var firstName = "张三";
String a = @$"hello {firstName}
豆瓣 111";
Console.Write($"{a}");
}
```
占位符
Console.WriteLine(“{0}sdlfsjlf”,变量);变量可占据0这个位置,多个变量,只需要增加数值就行。
C#foreach循环
```java
foreach(String s in str)
{
if (s.StartsWith("B"))
{
Console.WriteLine($"嫌疑{s}");
}
}
//java for(String s : str){}
```
类型转换
使用 Convert.ToInt32() 进行转换时,文本浮点数值将正确地向上舍入到 2。 如果你将文本值更改为 1.499m,则会向下舍入到 1。
int atos = 11;
String num = "22";
String f = "1";
int res1 = int.Parse(num)*atos;
String res2 = Convert.ToString(atos);
Console.WriteLine(@$"类型:{res1.GetType().Name} 值:{res1}");
Console.WriteLine(@$"类型:{res2.GetType().Name} 值:{res2}");
Console.WriteLine(Convert.ToInt32(1.5f));
//类型:Int32 值:242
//类型:String 值:11
//2
-
判断转换
对于字符串转换成int类型,如不是数值问题就会转换失败,我们可以使用TryParse()来判断
out 参数提供了返回值的方法的辅助手段。 在这种情况下,out 参数返回转换后的值public static void test1() { String str1 = "11ab"; String str2 = "22"; int result = 0; if (int.TryParse(str2,out result)) { Console.WriteLine("转换成功==》" + result); } else { Console.WriteLine("转换失败"); } }
操作数组
-
数组
Array.sort();//排序 Array.reverse();//反转 Array.clear();//删除 Array.resize();//改变大小 ... 这些方法和java个别是有差异的
内置方法
- indexof() ,LastIndexOf(),IndexOfAny()
- remove(),replace()
格式设置
方法
-
out参数
当一个方法需要返回多个不同类型的返回值时,可以使用out作为返回参数。一旦定义了out返回参数,就需要在方法内赋值。方法外需要定义接受,名字可不同。
static void Main(string[] args) { int[] nums = { 4, 2, 1, 9 }; string name1; nums = getNumsRef(nums, out name1); Console.WriteLine(name1); Console.WriteLine($"最大值={nums[1]},最小值={nums[0]}"); } /// <summary> /// out 参数练习 /// </summary> /// <param name="nums">数组</param> /// <param name="name">返回参数</param> /// <returns>求最大值,最小值</returns> public static int[] getNumsRef(int[] nums, out string name) { name = "返回最大最小的方法名"; Array.Sort(nums); int[] refs = new int[2]; refs[0] = nums[0]; refs[1] = nums[nums.Length-1]; return refs; }
-
ref 参数
引用外部变量,可以将外部变量带入方法内部,然后再带出方法外部。要求方法外部必须定义赋值
static void Main(string[] args) { int num = 10; addMoney(ref num); Console.WriteLine(@"加完之后的值:{0}",num);//110 } public static void addMoney(ref int num) { num += 100; }
-
命名参数:生命参数,以改变参数位置
public static void test6() { method1(age:11,name: "zhangsan"); } public static void method1(String name,int age) { Console.WriteLine($"名字:{name},年龄:{age}"); }
-
可变参数params
一个方法参数列表中只能出现一个可变参数,用户接受多个参数封装到一个数组中,且可变参数的位置必须是最后,才不会出现歧义。
static void Main(string[] args) { countArrNum("长度", 3, 4, 56, 10); } public static void countArrNum(string name,params int[] num) { Console.WriteLine(name+"->"+num.Length); }
-
声明参数:初始化参数值
public static void test6() { method1("lishi222"); } public static void method1(String name="lisi",int age=1) { Console.WriteLine($"名字:{name},年龄:{age}"); }
复杂类型
- const 修饰 是常量
枚举类型
-
枚举类型转换成int
namespace Test2 { public enum SEASON { spring, summer=5, autumn, winter } class Program { static void Main(string[] args) { #region 枚举类型转换成int SEASON s1 = SEASON.autumn; Console.WriteLine((int)s1); #endregion } } }
-
int转换成枚举
-
string转成成枚举
飞行棋小项目
- 飞行棋小项目 中的FlyGame项目
面向对象
属性
-
get和set方法简写
namespace _2024_0719_Project { class Person { private string _name;//字段 private int _age; public string Name//属性 { get { return _name; } set { _name = value; } } public int Age { get { return _age; } set { _age = value; } } public void speak() { Console.WriteLine("my name is {0},my age is {1}", this.Name, this.Age); } } }
c#中age为字段,Age为属性,当调用属性时会调用里面的get,set方法。
static void Main(string[] args) { Person p = new Person(); p.Age = 11; p.Name = "zhangsan"; p.speak(); //my name is zhangsan,my age is 11 }
构造函数,this关键字
一个类是有默认的构造函数,如果你在类中定义了构造函数,则默认的构造函数 就不复存在。构造函数调用本类的构造函数可以使用this关键字
class Student
{
private string name;
//main函数调用这个构造方法Student s = new Student("李四");
public Student(string name):this("张三",11)
{
this.Name = name;
Console.WriteLine("名字: {0} 年龄: {1}",Name,Age);//名字: 李四 年龄: 11
}
private int age;
public Student(string name,int age)
{
this.Name = name;
this.Age = age;
}
public Student(){}
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
}
可以看到,先执行this的构造函数,然后执行本构造函数
析构函数
析构函数程序结束执行,类中定义如下
~Student()
{
Console.WriteLine("我是析构函数");
Console.ReadKey();
}
命名空间
引用其他项目
- 引用其他项目:1.在项目依赖项中右击,选择添加项目引用 2.使用using 命名空间
值类型和引用类型
值类型:int double decimal struct enum…
引用:数组 类 string
构造方法
-
子类继承父类 : 子类:父类
-
子类继承不了父类的私有
-
子类继承父类,可以访问父类的共有的属性,字段,方法
当调用子类的无参构造方法,首先是创建父类,调用父类的构造方法(如果父类中定义了有参构造方法,则必须定义父类无参构造方法以便创建)
子类为什么能访问父类的方法,肯定是提前创建了父类对象。class Program { static void Main(string[] args) { Stu stu = new Stu("张三", 11); stu.CommonWalk(); Console.WriteLine(stu.Name); } } public class Person { private string personName; private string name; public int age; public Person(string name, int age) { this.name = name; this.age = age; } public int Age { get => age; set => age = value; } public string Name { get => name; set => name = value; } public void CommonWalk() { Console.WriteLine("通用方法"); Console.ReadKey(); } } //继承 public class Stu : Person { private string name; public int age; //显示调用父类有参构造方法创建父类对象 public Stu(string name, int age) : base(name, age) { } public string Name1 { get => name; set => name = value; } }
控制台打印:
通用方法
张三
里氏转换
-
子类可以赋值给父类;父类可以强转成其子类;
-
is 关键字判断是否是此类型
static void Main(string[] args) { Person[] person = new Person[2]; person[0] = new Stu(); if(person[0] is Stu) { person[0].pSpeak();//父类只可以调用自己的 Stu stu = (Stu)person[0]; stu.stuSpeak(); } }
集合
- Add 添加单个 AddRange添加多个
- Clear清空所有元素 Remove 删除单个 RemoveAt根据下标删除 RemoveRange:根据下标移除范围内的元素
- Sort 比较排序 Rerverse 反转
- Insert:在指定位置插入元素 InsertRange
- Contains 判断是否包含
- count 实际包含长度 capacity 可包含长度
数组和集合的转换
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace _5_Project
{
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
int[] arr = list.ToArray();//list 转数组
list = arr.ToList();//数组转list
foreach (var de in list)
{
Console.Write(de + " ");
}
}
}
}
Hashtable
Hashtable hashtable = new Hashtable();
hashtable.Add(1, "张三");
hashtable.Add(false, "李四");
foreach(var key in hashtable.Keys)
{
Console.WriteLine($@"key:{key} value {hashtable[key]}");
}
字典(Dictionary)
-
适合定义泛型
static void Main(string[] args) { Dictionary<int, string> dic = new Dictionary<int, string>(); dic.Add(1, "张撒"); dic.Add(2, "李四"); foreach (KeyValuePair<int,string> kv in dic) { Console.WriteLine(@$"键---{kv.Key},值---{kv.Value}"); } }
File
Directroy(文件夹操作类)
- CreateDirectory:创建文件夹
- Delete:删除文件夹
- Move:剪切文件夹
- GetFiles:获取指定文件下所有文件的全路径,重载可筛选文件*.jpg
- Exist:判断文件夹是否存在
Path(文件路径操作类)
static void Main(string[] args)
{
string p = @"D:\周报\周周报.xlsx";
Console.WriteLine("文件名包括扩展 {0}",Path.GetFileName(p));
Console.WriteLine("文件名不包括扩展 {0}", Path.GetFileNameWithoutExtension(p));
Console.WriteLine("获取扩展名 {0}", Path.GetExtension(p));
Console.WriteLine("获取文件所在文件夹 {0}", Path.GetDirectoryName(p));
Console.WriteLine("获取全路径 {0}", Path.GetFullPath(p));
}
- File.Create File.Delete File.Copy File.Move … 网上搜相关方法
读写数据
-
读 ReadAllBytes:有注释
-
写:WriteAllBytes
//获取字符串的字节 byte[] buff = Encoding.GetEncoding("UTF-8").GetBytes("你好酒店房间打开,d"); File.WriteAllBytes(@"E:\测试\a.txt",buff);//写入指定路径 Console.WriteLine("写入成功");
File还有很多好用的方法,可查API
文件流
File由于是一次操作文件,对性能消耗比较大
FileStream(字节操作)
读
//创建流,打开或创建,可读权限
FileStream fileStream = new FileStream(@"E:\测试\aa.txt",FileMode.OpenOrCreate,FileAccess.Read);
byte[] buff = new byte[1024];
int r = fileStream.Read(buff,0,buff.Length);//返回读到的位置,读多少个
string msg = Encoding.GetEncoding("UTF-8").GetString(buff, 0, r);
//关闭
fileStream.Close();
fileStream.Dispose();
Console.WriteLine(msg);
写
//写
//using框架会帮我们自动关闭流资源
using (FileStream fileStream1 = new FileStream(@"E:\测试\aa.txt", FileMode.Append, FileAccess.Write))
{
byte[] buff1 = Encoding.UTF8.GetBytes("我是写入的数据");
fileStream1.Write(buff1, 0, buff1.Length);
Console.WriteLine("写入成功");
}
StreaReader和StreamWriter
读
//读
using (StreamReader streamReader = new StreamReader(@"E:\测试\aa.txt", Encoding.UTF8))
{
while (!streamReader.EndOfStream)
{
string str = streamReader.ReadLine();
Console.WriteLine(str);
}
}
写
//写,true为追加
using (StreamWriter streamWriter = new StreamWriter(@"E:\测试\b.txt",true))
{
streamWriter.WriteLine("这是我写的");
Console.WriteLine("写完了");
}
多态实现形式
虚方法
在子类要重写的方法的父类中用virtual关键字修饰,子类的方法用override修饰
using System;
namespace _9_Project
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Stu();
p1.speak();//可以看到这里不调用父类的方法,而是子类的
}
}
class Person
{
public virtual void speak()
{
Console.WriteLine("我是人类");
}
}
class Stu : Person
{
public override void speak()
{
Console.WriteLine("我是子类学生");
}
}
}
抽象类
序列化和反序列化
-
在类的上一行[Serializable] 表示可序列化
//序列化 Person p = new Person("张三",11); using (FileStream writer =new FileStream(@"E:\测试\c.txt",FileMode.OpenOrCreate,FileAccess.Write)) { BinaryFormatter binaryFormat = new BinaryFormatter(); binaryFormat.Serialize(writer, p); } //反序列化 using(FileStream reader = new FileStream(@"E:\测试\c.txt", FileMode.OpenOrCreate, FileAccess.Read)) { BinaryFormatter binaryFormat = new BinaryFormatter(); Person p2 = (Person)binaryFormat.Deserialize(reader); Console.WriteLine($@"名字=》{p2.Name} 年龄=>{p2.Age}"); }
密封部分类
- 使用sealed修饰类,表示此类不可被继承
- 使用partial修饰类,表示此类是部分类,几个部分类共享彼此的数据
MD5加密
static void Main(string[] args)
{
MD5 md5 = MD5.Create();
String str = "我是加密的字符串";
byte[] buff1 = Encoding.UTF8.GetBytes(str);
buff1= md5.ComputeHash(buff1);
string append = "";
for(int i = 0; i < buff1.Length; i++)
{
append += buff1[i].ToString("x");//转换16进制
}
Console.WriteLine(append.ToString());
}