c# 实用精华知识点全解
本文介绍c#的实用知识点
写在前面(通识)
- vs常用快捷键 - F5 调试运行程序
 ctrl F5 不调试运行程序
 F11 逐条语句调试
 F10 逐过程调试程序
 注释快捷键 ctrl + k + c
 代码格式化 ctrl + A + k + F
 强制智能提示 ctrl + J
 
- 面相对象语言三大特性 - 封装性,重复代码共用
 继承性,类,接口等的继承
 多态性,不同的子类调用父类的方法,执行效果不一样
 
- c#中的访问修饰符 - private 本类内部可以使用
 protected 本类内部和子类内部可以使用
 internal 当前程序集中可用
 protected internal 当前程序集中,并且是的当前类和子类内部可用
 public 访问无限制
 类成员不写访问修饰符默认是private
 类不写访问修饰符默认是internal
 命名空间中定义的成员只能是public或者internal
 
- 属性和字段 - private string _str = "aaa"; // 字段
 internal int num { get; set; } // 属性
 
- 方法的重载 - 方法名相同,只要参数类型、个数或者顺序不同时就认为是不同的函数
 
- 泛型 - 泛型是C#中的一大特色,也是基础
 泛型就是将类型参数化
 泛型参数可以使用where做进一步限制
 where T: someClass 限制T是继承自someClass类的
 where T: new() 限制T是可以实例化的
 where T: someInterface 限制T是继承自someInterface接口的
 where T: U 限制T是继承自其他类型参数的
 使用demo
 public class Demo1<T>: Test1<T> where T: Test2 { }
 public interface Test1<T>: Test2 { }
 public interface Test2 { }
 泛型方法 public void Fn<T>(T[] a) { }
 
- 测量代码的运行时间 - Stopwatch watch = new Stopwatch();
 watch.Start();
 // ...
 watch.Stop();
 TimeSpan time = watch.Elapsed;
 
- 生成guid - String str = Guid.NewGuid().ToString();
 
- 嵌套引号的写法 - string str = @"aaaa""aa""";
 
- 扩展方法 - 指定任意一个顶级静态类就可以定义任意类型的扩展方法
 定义扩展方法
 public static class Demo
 {
 public static void Fn(this int a)
 {
 Console.WriteLine("aa");
 }
 }
 使用扩展方法
 int num = 222;
 num.Fn();
 
c#基础
- 变量 - 声明变量 - 声明变量 string str1 = 'aa', str2
 添加?号,表示可以赋值null,int? i = 1; 等价于 Nullable<int> a = null;
 - 成员变量 - static string str;
 string str1;
 public void Fn()
 {
 str = "aaa";
 str1 = "bbb";
 }
 - 局部变量 - 在代码块中定义的变量,只在代码块中有效
 嵌套的子作用域中不能有父作用域中的同名变量
 
- 常量 - const string str2 = "aaa";
 在声明的时候必须赋值,并且后续无法修改
 
- 数据类型 - 值类型 - 整数类型
 sbyte -128~127
 byte 0~255
 short -32768~327767
 ushort 0~65535
 int -2147483648~2147483647
 uint 0~4294967295
 long -9223372036854775808~-9223372036854775807
 ulong 0~18446744073709551615
 浮点类型
 float 整数位和小数位加起来最大不超过7位数
 double 整数位和小数位加起来最大不超过15位数
 默认情况下都是double类型,要使用float类型必须强转
 double num = 1.2;
 float num1 = 1.3f;
 float num2 = 1.4F;
 float num3 = (float)num;
 布尔类型
 bool a = true;
 字符类型
 表示单个字符
 char c = 'a';
 char.IsLetterOrDigit(c); // 判断字符是不是字母和数字
 结构类型
 声明结构
 public struct Person
 {
 const int Age = 18; // 声明常量
 public string Name; // 声明变量,不能指定初始值
 public Person(string name) // 构造函数
 {
 Name = name;
 }
 public string Fn() // 声明方法
 {
 return Name;
 }
 }
 使用结构
 不使用new
 Person demo;
 demo.Name = "小叶";
 使用new
 Person demo = new Person("小叶");
 Console.WriteLine(demo.Fn());
 - 引用类型 - class类
 ** 构造函数和析构函数
 构造函数使用new自动调用
 静态构造函数
 不能使用访问修饰符
 不能传递参数
 使用此类立即自动调用构造函数,并且只会调用一次
 析构函数,当此类即将被程序销毁时调用
 public class Demo
 {
 public Demo() // 构造函数
 {
 Thread.Sleep(3000);
 Console.WriteLine("构造函数执行了");
 }
 ~Demo()
 {
 Console.WriteLine("析构函数执行了");
 }
 }
 ** 类的继承
 基本写法
 public class Demo1
 {
 protected string _Name { get; set; } = "小叶";
 public void Fn() { }
 }
 public class Demo2 : Demo1
 {
 public void SayHello()
 {
 base.Fn(); // base访问父类中的成员
 Console.WriteLine("你好" + _Name);
 }
 }
 构造函数的继承
 父类中有包含参数的构造函数子类无法继承,子类继承需要父类无参数构造函数
 解决办法如下
 重新实现一个无参数构造函数
 public class Demo1
 {
 public Demo1(string str) { }
 public Demo1() { }
 // public Demo1(): this("aaa") { }
 }
 public class Demo2 : Demo1 { }
 使用base给父类构造函数传递参数
 public class Demo1
 {
 public Demo1(string str) { }
 }
 public class Demo2 : Demo1
 {
 public Demo2(string str) : base(str) { }
 }
 ** 隐藏方法
 当子类中有和父类中方法同名的方法时,最好使用new隐藏
 public class Demo1
 {
 public void Fn() { Console.WriteLine("aa"); }
 }
 public class Demo2 : Demo1
 {
 public new void Fn() { Console.WriteLine("bb"); }
 }
 ** 虚方法
 除了可以使用new隐藏外,还可以使用override重写virtual方法
 public class Demo1
 {
 public virtual void Fn() { Console.WriteLine("aa"); }
 }
 public class Demo2 : Demo1
 {
 public override void Fn() { Console.WriteLine("bb"); }
 }
 ** 抽象类
 抽象类无法实例化
 抽象方法只能在子类中使用override实现
 抽象方法不能使用virtual,static,private
 public abstract class Demo1
 {
 public abstract void Fn();
 }
 public class Demo2 : Demo1
 {
 public override void Fn() { }
 }
 ** 密封类
 密封类无法继承,不能使用abstract
 密封类成员使用protected和virtual无意义
 密封方法必须是override父类的方法
 public sealed class Demo2: Demo1
 {
 public sealed override void Fn()
 {
 base.Fn();
 }
 }
 ** 分布类
 当你想把一个类像命名空间一样分布在多个文件中,那么分布类是你唯一的选择
 public partial class Demo
 {
 public int _num1 = 1;
 }
 public partial class Demo
 {
 public int _num2 = 2;
 }
 简直就是黑科技
 ** 使用操作符简写类实例化过程
 public class Demo
 {
 int Num { get; set; }
 public static implicit operator Demo(int num)
 {
 return new Demo() { Num = num };
 }
 }
 使用 Demo text = 11; 即可初始化一个Demo实例
 ** 类的浅拷贝
 public class Demo
 {
 public int Age { get; set; }
 public int Name { get; set; }
 public Demo ShallowCopy()
 {
 return this.MemberwiseClone() as Demo;
 }
 }
 ** 类的深拷贝
 [Serializable]
 public class Demo
 {
 public int Age { get; set; }
 public int Name { get; set; }
 public Demo DeepCopy ()
 {
 BinaryFormatter bf = new BinaryFormatter();
 using(MemoryStream ms = new MemoryStream())
 {
 bf.Serialize(ms, this);
 ms.Position = 0;
 return bf.Deserialize(ms) as Demo;
 }
 }
 }
 字符串类型
 string str = null; // 空字符串
 string str = string.Empty; // 0长度字符串
 ** 比较两个字符串是否相等
 str1 == str2
 str1.CompareTo(str2) // 相等返回0,str1大于str2返回1,小于返回-1
 string.Equals(str1, str2) // 相等返回true,不等返回false
 str1.Equals(str2)
 string.Compare(str1,str2[,true]) // 相等返回0,str1大于str2返回1,小于返回-1。第三个可选的布尔值,如果true表示忽略大小写
 ** 字符串格式化
 一般字符串格式化
 string str = string.Format("{0},{1}!", "aa", "bb"); // aa,bb!
 日期格式化
 string str = string.Format("{0:D}", DateTime.Now); // 2017年12月31日
 相关的格式化参数如下
 d 表示YYYY-MM-dd
 D 表示YYYY年MM月dd日
 t 表示hh:mm
 T 表示hh:mm:ss
 f 表示YYYY年MM月dd日 hh:mm
 F 表示YYYY年MM月dd日 hh:mm:ss
 g 表示YYYY-MM-dd hh:mm
 G 表示YYYY-MM-dd hh:mm:ss
 M或者m 表示 MM月dd日
 Y或者y 表示YYYY年MM月
 ** 字符串截取
 string str = "C#好简单啊".Substring(0, 2);
 从索引为0的位置开始截取2个字符
 ** 分割字符串
 string str = "今天是|元旦佳节,一个!人";
 string[] arr = str.Split(new char[] { '|', ',', '!' });
 // ["今天是", "元旦佳节", "一个", "人"]
 ** 插入字符串
 string str = "aaaccc".Insert(3, "bbb"); // aaabbbcc
 ** 字符串填充
 string str = "a".PadLeft(7,'a'); // aaaaaaa
 string str = "a".PadRight(7,'b'); // abbbbbb
 第一个参数是填充后的总字符串长度
 ** 删除字符串
 string str = "abcdef".Remove(2); // ab 从索引位2开始删
 string str = "abcdef".Remove(2, 2); // abef 从索引位2开始删,删除两个字符
 ** 字符串复制
 copy复制 string str = string.Copy("aaa");
 CopyTo复制,将字符串的一部分复制到字符数组中
 char[] result = new char[10];
 "aaaa".CopyTo(1, result, 1, 2);
 参数一,字符串的开始索引
 参数二,字符数组
 参数三,字符数组中的起始索引
 参数四,字符串要复制的字符个数
 ** 字符串替换
 string str = "abs,dg".Replace(',', char.MinValue);
 ** 字符串去首位空格
 str.Trim();
 ** 字符串转成字符数组
 string str = "你好吗?";
 char[] arr = str.ToCharArray();
 str = new string(arr); // 字节数组转字符串
 ** 字符串转成字节数组
 byte[] arr = Encoding.UTF8.GetBytes("agagteg");
 ** 字节转成字符串
 string str = Encoding.UTF8.GetString(new byte[] { 1, 2, 3, 4 });
 ** 字符串常量池
 由于字符串的不可变性,所有的字符串的引用都存储在池中
 string str = String.Intern("aaa"); // 用于在池中查找字符串的引用,如果存在则直接返回引用,如果不存在则创建字符串并且返回引用
 string str = String.IsInterned("aaa"); // 如果存在返回引用,如果不存在返回null
 stringBuilder类型
 string对象创建后是不可变的,stringBuilder的作用是创建可变的字符串
 StringBuilder str = new StringBuilder("aaabbbccc", 10); // 创建10个字符长度的字符串
 str.Append("ddd"); // 追加
 str.AppendFormat("{0}!!!!", "ddd"); // 格式化后追加
 str.Insert(9, "ddd"); // 在指定索引位插入字符串
 str.Remove(0, 3); // 指定开始索引位删除指定个数的字符
 str.Replace("ccc", "!"); // 字符串替换
 DateTime类型
 DateTime time = DateTime.Now; // 获取系统的当前时间
 DateTime time = DateTime.Today; // 获取当前日期
 DateTime time = DateTime.Today.AddDays(1); // 获取明天的日期
 DateTime time = new DateTime(2017, 10, 3); // 设置日期
 DateTime time = DateTime.Parse("2017-10-13"); // 将字符串转成日期
 int part = time.Year; // 获取年
 int part = time.Month; // 获取月
 int part = time.Day; // 获取天
 int part = time.Hour; // 获取时
 int part = time.Minute; // 获取分钟
 int part = time.Second; // 获取秒
 Random类型
 Random random = new Random();
 int number = random.Next(); // 生成任意随机数
 int number = random.Next(100); // 生成小于100的随机数
 int number = random.Next(0, 10); // 生成0~10之间的随机数
 委托类型
 委托就是用来表示匿名函数的类型
 基本原理
 static void Main(string[] args)
 {
 Dlg d = new Dlg(Fn); // 或者 Dlg d = Fn;
 d(); // 或者 d.Invoke();
 Console.ReadKey();
 }
 public delegate void Dlg(); // 声明委托
 public static void Fn() { Console.WriteLine("调用了"); }
 当做类型使用
 public delegate void Dlg();
 public static void Fn(Dlg fn) { fn(); }
 当做匿名函数使用
 Dlg fn = delegate () { };
 Dlg fn = () => { };
 public delegate void Dlg();
 泛型委托
 Dlg<string> fn = (str) => { };
 public delegate void Dlg<T>(T str);
 内置委托类型
 Action类型,没有返回值 Action<string> Fn = (str) => { };
 Func类型,有返回值 Func<int, string, string> Fn = (a, b) => a + b;
 多播委托
 Action fn = () => { Console.WriteLine(1); };
 fn += () => { Console.WriteLine(2); };
 fn += () => { Console.WriteLine(3); };
 事件委托
 事件委托使用event关键字修饰,在外界赋值要使用+=或者-=,并且只能在类的内部调用
 public static class Demo
 {
 public static event Action Fn;
 static void Fn1() { Fn(); } // 外界无法调用此委托
 }
 Demo.Fn += () => { Console.WriteLine(3); }; // 外界赋值只能这样赋值
 异步委托
 Func<int, int> fn = a =>
 {
 Thread.Sleep(2000);
 return a;
 };
 IAsyncResult ir = fn.BeginInvoke(2, a => {
 // 此处的回调函数,c#会单独开辟一个线程执行
 Console.WriteLine(a.AsyncState);
 }, "我是回调函数的参数");
 Console.WriteLine(fn.EndInvoke(ir)); // 此处阻塞当前主线程,等待执行完毕
 if (ir.IsCompleted)
 {
 Console.WriteLine("执行完成");
 }
 Console.WriteLine("主线程");
 上面代码的执行结果如下
 2
 执行完成
 我是回调函数的参数 // 此结果执行时机不确定
 主线程
 - 枚举类型 - 枚举的作用就是使用属性代表数值,增加程序的可读性
 枚举,默认从0开始一次递增,可以手动赋值
 enum myEnum
 {
 first,
 seconde,
 third
 }
 (int)myEnum.first // 0
 - 类型转换 - 隐式转换,低精度的值和隐式转换成高精度同类型的值,反过来不行
 显示转换
 将高精度值转成低精度
 long j = 2;
 int i = (int)j;
 或者
 long j = 2;
 int i = Convert.ToInt32(j);
 字符串转数字
 int.Parse("111");
 类型强转
 a as b // 容错处理
 装箱和拆箱
 将值类型转化成引用类型叫做装箱,反过来叫做拆箱
 装箱
 int i = 111;
 object obj = i;
 拆箱
 object i = 111;
 int obj = (int)i;
 - 相等比较 - ReferenceEquals
 比较引用,但是在比较字符串的时候比较的是值
 bool isEqual = object.ReferenceEquals(new { }, new { }); // false
 Equals
 比较值
 1.Equals(2);
 ==
 比较值
 1 == 2
 
- 表达式和运算符 - 算数运算符 + - * / %
 赋值运算符 = += -= /= *= %=
 关系运算符 > < == >= <= !=
 逻辑运算符 && || ! &
 && 当等式左边为false,不会再计算等式右边
 & 等式左右两边都会计算
 内置运算符
 is判断数据类型 bool test = 11 is object;
 三元运算符 false ? 1 : 2;
 new运算符,创建实例
 typeof运算符,获取类型的类型,Type result = typeof(int);
 
- 流程控制语句 - if-else-if
 switch-case
 while
 do...while
 for
 foreach
 可以使用跳转语句,控制流程
 break 结束循环
 continue 执行下次循环
 return 立即结束
 goto 跳转到指定位置,控制更加精细
 在普通的循环中使用
 int[] arr = new int[] { 1, 2, 3, 4, 5 };
 foreach(int item in arr)
 {
 if(item == 3)
 {
 goto finished;
 }
 }
 finished:
 Console.WriteLine("执行完成");
 Console.WriteLine("goto语句执行后的语句");
 在switch结构中使用
 switch(3)
 {
 case 1: Console.WriteLine(1); goto default;
 case 2: Console.WriteLine(2); break;
 case 3: Console.WriteLine(3); goto case 2;
 default: Console.WriteLine("default");
 }
 
- 索引器 - 索引器可以方便的访问类的成员
 声明索引器
 public class Demo
 {
 string[] str = new string[] { "aa", "bb", "cc" };
 public string this[int i] { get => str[i];set => str[i] = value; }
 }
 使用索引器
 Demo test = new Demo();
 test[1] = "dd";
 string str = test[1];
 
c#基础升级
- 数组(不可变) - 一维数组 - 声明数组 int[] arr = new int[5];
 声明一维数组,元素是数组
 int[][] arr = new int[2][];
 arr[0] = new int[2];
 arr[1] = new int[3];
 初始化数组
 int[] arr = new int[5] { 1, 2, 3, 4, 5 };
 int[] arr = { 1, 2, 3, 4, 5 };
 数组排序 Array.Sort(arr); // 升序排序
 数组反转 Array.Reverse(arr); // 反转排序
 - 二维数组 - 声明二维数组
 int[,] arr = new int[2, 3]; // 两行三列
 二维数组的赋值
 int[,] arr = new int[,] { { 1, 2 }, { 3, 4 } };
 Console.WriteLine(arr[1, 0]); // 3
 二维数组的遍历
 int[,] arr = { { 1, 2 }, { 3, 4 } };
 使用for遍历
 for(int i = 0; i < arr.GetLength(0); i++)
 {
 // 数组的每一行
 for(int j = 0; j < arr.GetLength(1); j++)
 {
 // 数组每一行的每一个元素
 Console.WriteLine(arr[i, j]);
 }
 }
 使用foreach快速遍历
 作用和for遍历一致
 foreach(int item in arr)
 {
 Console.WriteLine(item);
 }
 
- ArrayList(可以方便的操作数组) - 声明 - ArrayList arr = new ArrayList();
 ArrayList arr = new ArrayList(5);
 ArrayList arr = new ArrayList(new int[] { 1, 2, 3, 4, 5 });
 - 实例属性 - 列举部分属性
 arr.Capacity; // 获取或者设置数组的容量
 arr.Count; // 获取数组的元素个数
 arr.IsFixedSize; // 数组是否固定大小
 - 实例方法 - arr.Add(6); // 添加元素
 arr.Insert(5, 6); // 指定索引位置5插入元素6
 arr.InsertRange(5, new int[] { 6, 7, 8 }); // 插入多个
 arr.Clear(); // 清空
 arr.Remove(5); // 删除指定元素
 arr.RemoveAt(4); // 删除指定索引的元素
 arr.RemoveRange(3, 2); // 从索引位置为3开始删除两个元素
 int index = arr.IndexOf(3); // 查找指定元素3第一次出现的索引
 int index = arr.LastIndexOf(3); // 查找指定元素3最后一次出现的索引
 bool isHave = arr.Contains(3); // 是否包含指定元素
 foreach(int item in arr){} // 遍历
 
- List(泛型集合) - 声明和ArrayList一样也有三种方式,不再赘述
 List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
 方法使用(列举部分)
 list.Remove(5); // 指定元素删除
 list.Insert(5, 6); // 指定索引5插入元素6
 list.RemoveAll(item => item == 5); // 指定条件移除
 list.RemoveAt(4); // 指定索引移除
 list.Clear(); // 清空
 string str = String.Join("|", list); // 拼接成字符串
 int[] arr = list.ToArray(); // 转化成数组
 foreach(int i in list){} // 遍历
 list.ForEach(item => Console.Write(item)); // 遍历
 属性
 list.Count; // 数组长度
 
- Hashtable(键值对集合) - 声明 Hashtable obj = new Hashtable();
 属性 obj.Count; // 个数
 方法
 obj.Add("Name", "小叶"); // 添加元素
 obj.Clear(); // 清空
 obj.Remove("Name"); // 删除元素
 bool isHave = obj.Contains("Name"); // 是否包含键
 bool isHave = obj.ContainsValue("小叶"); // 是否包含值
 遍历
 foreach(DictionaryEntry entries in obj)
 {
 var key = entries.Key; // 键
 var value = entries.Value; // 值
 }
 
- Dictionary - 声明Dictionary实例 Dictionary<string, string> obj = new Dictionary<string, string>();
 添加成员 obj.Add("a", "aaa");
 访问成员 obj["a"];
 遍历成员
 根据键遍历 foreach(string item in obj.Keys) { }
 根据值遍历 foreach(string item in obj.Values) { }
 根据键值对遍历 foreach(KeyValuePair<string, string> item in obj) { }
 
- 方法参数 - 一般传参
 public static void Fn(int[] arr) { }
 Fn(new int[] { 1, 2, 3 });
 使用params修饰符
 public static void Fn(params int[] arr) { }
 Fn(new int[] { 1, 2, 3 });
 Fn(1, 2, 3);
 两种调用方式等价
 使用ref修饰符
 将值类型的行为变成引用类型
 public static void Fn(ref int num) { num = 111; }
 调用,将num的值改成111了
 int num = 1;
 Fn(ref num);
 使用out修饰符
 public static void Fn(out int num) { num = 111; }
 调用,out的作用和ref类似,设计out的目的就是将一个变量在方法体内赋值,而设计ref的目的是在方法体内改变值
 int num;
 Fn(out num);
 
- 异常处理 - try
 {
 throw new Exception("aa");
 }catch(Exception ex)
 {
 // 捕获异常
 Console.WriteLine(ex.Message);
 throw; // 错误向方法的调用者抛出
 }
 finally
 {
 // 始终都会执行
 }
 
- 接口 - 基本使用 - 类只能继承一个抽象类,使用接口没有限制
 接口中只定义声明,子类实现这些声明,并且是public
 接口可以继承其他接口
 接口成员不能使用权限修饰符
 interface Test
 {
 string Name { get; set; }
 void Fn();
 }
 public abstract class Demo1: Test
 {
 public string Name { get; set; }
 public abstract void Fn();
 }
 - 显示实现接口 - 当多个接口中有同名方法,这是就要使用显示接口了
 显示实现接口类的成员不能使用任何的修饰符
 public abstract class Demo1: Test1, Test2
 {
 string Test1.Name { get; set; }
 string Test2.Name { get; set; }
 void Test1.Fn() { }
 void Test2.Fn() { }
 }
 interface Test1
 {
 string Name { get; set; }
 void Fn();
 }
 interface Test2
 {
 string Name { get; set; }
 void Fn();
 }
 
- 迭代器 - 迭代器就是foreach语句,迭代器能够操作的对象是实现了IEnumerator接口的对象
 第一种遍历器
 实现一个可迭代对象
 public class Demo1 : IEnumerable
 {
 public IEnumerator GetEnumerator()
 {
 yield return "a";
 yield return "b";
 yield return "c";
 yield break;
 }
 }
 使用迭代器遍历
 Demo1 test = new Demo1();
 foreach(string item in test)
 {
 Console.WriteLine(item);
 }
 第二种遍历器
 实现一个可迭代对象
 public class Demo : IEnumerable
 {
 string[] arr = new string[] { "a", "b", "c" };
 public IEnumerator GetEnumerator()
 {
 return new Demo1(arr);
 }
 }
 实现一个枚举类
 public class Demo1 : IEnumerator
 {
 string[] arr;
 int index = -1;
 public Demo1(string[] arr) { this.arr = arr; }
 public object Current => arr[index];
 public bool MoveNext()
 {
 if(index+1 < arr.Length)
 {
 index++;
 return true;
 }
 return false;
 }
 public void Reset() { index = -1; }
 }
 使用foreach迭代
 Demo demo = new Demo();
 foreach(var item in demo)
 {
 Console.WriteLine(item);
 }
 
- 文件流 - File类 - 文件操作的一些静态方法
 复制文件 File.Copy("F:/学习实验区/c#/demo.txt", "F:/学习实验区/c#/copy/demo.txt");
 创建并覆盖文件 File.Create("F:/学习实验区/c#/demo.txt");
 删除文件 File.Delete("F:/学习实验区/c#/demo.txt");
 是否存在文件 File.Exists("F:/学习实验区/c#/demo1.txt");
 文件剪切 File.Move("F:/学习实验区/c#/demo1.txt", "F:/学习实验区/c#/demo2.txt");
 将demo.txt文件内容使用demo1.txt覆盖,并且将demo.txt文件备份成demo3.txt
 File.Replace("F:/学习实验区/c#/demo1.txt", "F:/学习实验区/c#/demo.txt", "F:/学习实验区/c#/demo3.txt");
 将文件读成字节数组 byte[] bytes = File.ReadAllBytes("F:/学习实验区/c#/demo.txt");
 将文件的内容读成字符串数组,一行就是一个元素 string[] arr = File.ReadAllLines("F:/学习实验区/c#/demo.txt");
 将文件读成字符串 string str = File.ReadAllText("F:/学习实验区/c#/demo.txt");
 创建文件并一行一行写入数据 File.WriteAllLines("F:/学习实验区/c#/demo4.txt", new string[] { "a", "b", "c" });
 创建文件并写入文本 File.WriteAllText("F:/学习实验区/c#/demo.txt", "你好");
 获取文件或者目录的创建时间 DateTime time = File.GetCreationTime("F:/学习实验区/c#/demo.txt");
 获取文件或者目录上次写入的时间 DateTime time = File.GetLastWriteTime("F:/学习实验区/c#/demo.txt");
 设置文件的创建日期 File.SetCreationTime("F:/学习实验区/c#/demo.txt", DateTime.Now);
 设置文件的上次访问时间 File.SetLastAccessTime("F:/学习实验区/c#/demo.txt", DateTime.Now);
 设置文件的上次写入时间 File.SetLastWriteTime("F:/学习实验区/c#/demo.txt", DateTime.Now);
 文件流一般处理
 写数据
 using(FileStream fs = File.Open("F:/学习实验区/c#/demo.txt", FileMode.Append, FileAccess.Write))
 {
 using(StreamWriter sw = new StreamWriter(fs))
 {
 sw.WriteLine("哈哈"); // 向文件中写入一行数据
 sw.WriteLine("你好");
 }
 }
 读数据
 using(FileStream fs = File.Open("F:/学习实验区/c#/demo.txt", FileMode.Open, FileAccess.Read))
 {
 using(StreamReader sr = new StreamReader(fs))
 {
 string str = sr.ReadToEnd();
 Console.WriteLine(str);
 }
 }
 文件流简化处理
 快速创建或打开一个文件,并写入数据
 using(StreamWriter sw = File.CreateText("F:/学习实验区/c#/demo.txt"))
 {
 sw.WriteLine("哈哈哈哈哈哈");
 }
 快速打开一个文件所有数据
 using(FileStream fs = File.OpenRead("F:/学习实验区/c#/demo.txt"))
 {
 using(StreamReader sr = new StreamReader(fs))
 {
 Console.WriteLine(sr.ReadToEnd());
 }
 }
 文件流分段读取
 一次性全读
 using(FileStream fs = File.OpenRead(@"F:\学习实验区\c#\demo.txt"))
 {
 byte[] bytes = new byte[fs.Length];
 fs.Read(bytes, 0, bytes.Length); // 将数据读取到bytes字节数组中
 Console.WriteLine(Encoding.UTF8.GetString(bytes));
 }
 分小段一点点读
 using(FileStream fsr = File.OpenRead(@"F:\学习实验区\c#\demo.txt"))
 {
 using(FileStream fsw = File.OpenWrite(@"F:\学习实验区\c#\test.txt"))
 {
 byte[] bytes = new byte[1];
 int r = 0;
 while((r = fsr.Read(bytes, 0, bytes.Length)) > 0)
 {
 fsw.Write(bytes, 0, r); // 追加写入数据
 // -----读取进度获取-----
 double percent = (fsw.Position * 100) / fsr.Length;
 Console.WriteLine(percent);
 }
 }
 }
 - FileInfo类 - 使用FileInfo类可以对多次重复操作相同文件简化操作
 列举部分
 创建实例 FileInfo fi = new FileInfo("F:/学习实验区/c#/demo.txt");
 创建StreamWriter实例 StreamWriter sw = fi.AppendText();
 获取文件创建时间 DateTime time = fi.CreationTime;
 获取上次访问时间 DateTime time = fi.LastAccessTime;
 获取上次写入时间 DateTime time = fi.LastWriteTime;
 获取父目录实例 DirectoryInfo di = fi.Directory;
 获取目录路径 string path = fi.DirectoryName;
 文件是否存在 bool isHave = fi.Exists;
 获取文件扩展名 string str = fi.Extension;
 获取文件完整路径 string str = fi.FullName;
 - Directory类 - Directory类用来操作文件夹
 创建文件夹 Directory.CreateDirectory("F:/学习实验区/c#/demo");
 删除文件夹 Directory.Delete("F:/学习实验区/c#/demo");
 文件是否存在 bool isHave = Directory.Exists("F:/学习实验区/c#/demo");
 目录剪切 Directory.Move("F:/学习实验区/c#/demo", "F:/学习实验区/c#/demo1");
 获取目录创建时间 DateTime time = Directory.GetCreationTime("F:/学习实验区/c#/demo");
 设置基路径 Directory.SetCurrentDirectory("F:/学习实验区/c#/demo"); Directory.GetFiles("./");
 获取指定路径的父目录 Directory.GetParent("F:/学习实验区/c#/demo");
 获取指定路径的文件 string[] str = Directory.GetFiles("F:/学习实验区/c#/demo");
 获取目录的子目录 string[] arr = Directory.GetDirectories("F:/学习实验区/c#/demo");
 获取盘符 string str = Directory.GetDirectoryRoot("F:/学习实验区/c#/demo");
 - DirectoryInfo类 - 使用DirectoryInfo类可以对多次重复操作相同目录简化操作
 创建实例 DirectoryInfo di = new DirectoryInfo("F:/学习实验区/c#/test");
 获取创建时间 di.CreationTime
 获取绝对路径 di.FullName
 获取文件名 di.Name
 - 压缩文件 - using(FileStream fsr = File.OpenRead(@"F:\学习实验区\c#\demo.txt"))
 {
 using(FileStream fsw = File.OpenWrite(@"F:\学习实验区\c#\demo.zip"))
 {
 using(GZipStream gs = new GZipStream(fsw, CompressionMode.Compress))
 {
 byte[] bytes = new byte[1024]; // 内存中缓存的数据大小
 int len = 0;
 while((len = fsr.Read(bytes, 0, bytes.Length)) > 0)
 {
 gs.Write(bytes, 0, len);
 }
 }
 }
 }
 - 解压文件 - using(FileStream fsr = File.OpenRead(@"F:\学习实验区\c#\demo.zip"))
 {
 using(GZipStream gs = new GZipStream(fsr, CompressionMode.Decompress))
 {
 using(FileStream fsw = File.OpenWrite(@"F:\学习实验区\c#\demo1.txt"))
 {
 byte[] bytes = new byte[1024];
 int len = 0;
 while ((len = gs.Read(bytes, 0, bytes.Length)) > 0)
 {
 fsw.Write(bytes, 0, len);
 }
 }
 }
 }
 - 加密文件 - using(FileStream fsr = File.OpenRead(@"F:\学习实验区\c#\demo.txt"))
 {
 using(FileStream fsw = File.OpenWrite(@"F:\学习实验区\c#\test.txt"))
 {
 byte[] bytes = new byte[1024];
 int len = 0;
 while((len = fsr.Read(bytes, 0, bytes.Length)) > 0)
 {
 // 加密逻辑,再次运行此加密逻辑可实现解密
 for(int i = 0; i < len; i++)
 {
 bytes[i] = (byte)(byte.MaxValue - bytes[i]);
 }
 fsw.Write(bytes, 0, len);
 }
 }
 }
 
- 路径操作 - string path = @"F:\学习实验区\c#\demo.txt";
 获取路径的文件名 string str = Path.GetFileName(path);
 获取文件扩展名 string str = Path.GetExtension(path);
 获取文件名不带扩展名 string str = Path.GetFileNameWithoutExtension(path);
 获取文件名以外的目录部分 string str = Path.GetDirectoryName(path);
 设置文件扩展名(内存) string str = Path.ChangeExtension(path, ".exe");
 返回随机文件名
 string str = Path.GetRandomFileName();
 也可以使用 DateTime.Now.ToFileTime()
 路径合并 string str = Path.Combine(path, path1);
 获取当前项目目录下文件的绝对路径 string str = Path.GetFullPath("demo.txt");
 返回系统临时目录绝对路径 string str = Path.GetTempPath();
 创建临时文件并且返回文件绝对路径 string str = Path.GetTempFileName();
 
- 序列化 - Json序列化 - 需要添加System.Web.Extensions引用
 JavaScriptSerializer js = new JavaScriptSerializer();
 可以序列化类的属性
 string s = js.Serialize(new Demo());
 - XML序列化 - 可以将类序列化成xml文件,[XmlIgnore]无视某个属性
 XmlSerializer xml = new XmlSerializer(typeof(Demo));
 using(FileStream fsw = File.OpenWrite(@"F:\学习实验区\c#\demo.xml"))
 {
 xml.Serialize(fsw, new Demo());
 }
 - 二进制序列化 - 序列化的类需要添加[Serializable],使用[NonSerialized]无视属性
 BinaryFormatter bf = new BinaryFormatter();
 using(FileStream fs = File.OpenWrite(@"F:\学习实验区\c#\demo.bin"))
 {
 bf.Serialize(fs, new Demo());
 }
 - 二进制反序列化 - 反序列化同样需要[Serializable]
 BinaryFormatter bf = new BinaryFormatter();
 using(FileStream fsr = File.OpenRead(@"F:\学习实验区\c#\demo.bin"))
 {
 Demo obj = bf.Deserialize(fsr) as Demo;
 }
 
- 正则表达式 - 元字符 - . -> 除了\n以外的任意单个字符
 [] -> 字符组,多个字符任意一个
 a-z -> a到z任意一个字符
 | -> 或,如 a(x|y)b,z|food 表示 z 或者 food,或优先级最低
 * -> 表示前面一个字符可以出现任意多次
 + -> 表示前面一个字符可以出现一次或者多次
 ? -> 表示前面一个字符可以出现零次或者一次
 {n} -> 表示前面一个字符可以出现指定的次数
 {n,} -> 表示前面一个字符可以出现至少n次
 {n,m} -> 表示前面一个字符可以出现至少n次,至多m次
 ^ -> 表示开头
 $ -> 表示结尾
 [^] -> 表示取反
 \d -> 0-9任意数字
 \D -> 0-9以外的其他字符
 \w -> a-zA-Z0-9任意字符
 \W -> a-zA-Z0-9以外的任意字符
 \s -> 表示不可见字符
 \S -> 表示所有可见字符
 - 正则基本使用 - string str = "这是2222什么23334这是啥9878我也不5555知道0987678";
 创建正则实例 Regex regex = new Regex(@"\d");
 是否匹配 bool isMatch = Regex.IsMatch("666", "[0-9]{3}");
 提取第一个匹配的元素 Match result = Regex.Match(str, @"\d+");
 提取所有匹配的元素 MatchCollection result = Regex.Matches(str, @"\d+");
 替换匹配的元素
 string result = Regex.Replace(str, @"\d+", string.Empty);
 string result = Regex.Replace("10/11/2017", @"(\d+)/(\d+)/(\d+)", "$3-$2-$1");
 匹配分组
 Match result = Regex.Match("aaa333", @"([a-z]+)(\d+)");
 Console.WriteLine("{0}-{1}-{2}", result.Groups[0], result.Groups[1], result.Groups[2]);
 和split结合使用
 string[] result = Regex.Split("this is me", @"\s");
 - 贪婪模式 - 正则表达式限定符默认按照多的匹配
 贪婪 Match match = Regex.Match("abbbb", "ab+"); // match.Value -> abbbb
 取消贪婪 Match match = Regex.Match("abbbb", "ab+?"); // match.Value -> ab
 - 英文单词边界 - 作用就是限定一个单词
 string result = Regex.Replace("a aa bv", @"\baa\b", "ccc");
 - 环视 - ?<= 表示向做看
 ?= 表示向右看
 Match result = Regex.Match("this is me", @"(?<= )is(?= )");
 - 反向引用 - string result = Regex.Replace("aaabbbccc", @"(.)\1+", "$1"); // abc
 - 使用委托方法 - string result = Regex.Replace("aaabbbccc", @"(a{3})", Fn);
 public static string Fn(Match match)
 {
 return match.Groups[1].Value + "-";
 }
 
- Type的使用 - 通过获取Type可以方便的获取类的相关参数
 通过实例获取Type Demo demo = new Demo(); Type tp = demo.GetType();
 通过类本身获取Type Type tp = typeof(Demo);
 获取父类的Type Type tp = tp.BaseType;
 获取类的所有public字段 FieldInfo[] t = tp.GetFields(); Console.WriteLine(t[0].Name);
 获取类的所有public属性 PropertyInfo[] t = tp.GetProperties();
 类似的还有 GetMethods,GetMembers...
 
- 反射 - 反射的作用就是通过不导入程序集的方式,获取程序中的内容
 获取程序集 Assembly asb = Assembly.LoadFile(@"test.exe");
 获取所有的类 Type[] tps = asb.GetTypes();
 获取所有的public类 Type[] tps = asb.GetExportedTypes();
 获取指定类 Type tp = asb.GetType("ConsoleApp1.Demo");
 获取指定public方法 MethodInfo mi = tp.GetMethod("Fn");
 获取实例对象
 无参数构造函数
 object obj = Activator.CreateInstance(tp);
 调用方法 tp.Invoke(obj, new object[] { "aaa" });
 有参数构造函数
 var obj = tp.GetConstructor(new Type[] { typeof(string) });
 调用方法 object result = obj.Invoke(new object[] { "aaa" });
 
- 线程 - 线程的使用 - Thread tr = new Thread(() =>
 {
 while (true)
 {
 Console.WriteLine("新创建的线程");
 Thread.Sleep(1000);
 }
 }); // 创建线程
 tr.Start(); // 运行线程
 tr.IsBackground = true; // 设置线程为后台线程
 tr.Priority = ThreadPriority.Highest; // 设置线程优先级
 tr.Abort(); // 结束线程
 tr.Join(2000); // 单独执行此线程2秒,然后和主线程一起执行
 tr.ManagedThreadId // 线程的id
 Thread.CurrentThread.ManagedThreadId // 主线程id
 - 线程池的使用 - 线程池默认是后台线程,速度更快
 ThreadPool.QueueUserWorkItem(a =>
 {
 Console.WriteLine(a);
 }, "你好");
 获取最大线程数,和实际最大线程数
 int a, b;
 ThreadPool.GetMaxThreads(out a, out b);
 Console.WriteLine(a + "|" + b);
 
- socket编程(端口可以使用49152到65535) - Socket sk = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建socket对象
 IPAddress ia = IPAddress.Parse("192.168.31.198"); // 根据ip地址,创建IPAddress实例
 IPEndPoint ie = new IPEndPoint(ia, int.Parse("8881"));
 sk.Bind(ie); // 将ip和端口使用socket对象绑定
 sk.Listen(10); // 开始监听,允许同时连接10个
 while (true)
 {
 Socket proxSk = sk.Accept(); // 等待客户端的接入,阻塞当前线程,返回新的Socket对象
 Console.WriteLine(proxSk.RemoteEndPoint.ToString()); // 获取远程连接客户端的信息
 byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
 proxSk.Send(bytes, 0, bytes.Length, SocketFlags.None); // 给连接的客户端发送信息
 proxSk.Close();
 //proxSk.Shutdown(SocketShutdown.Both); // 关闭接受和连接的socket实例
 }
 
- async和task的用法 - 简单的异步任务
 public async Task<string> Fn(string str)
 {
 return await Fn1(str);
 }
 Task<string> Fn1(string str)
 {
 Thread.Sleep(3000);
 return Task.FromResult(str);
 }
 使用上面创建的任务
 Program test = new Program();
 Console.WriteLine("1");
 var result = test.Fn("aa"); // 执行任务,等待任务执行完成
 Console.WriteLine("2");
 Console.WriteLine(result.Result); // 获取任务的返回值
 Console.WriteLine("3");
 Console.ReadKey();
 执行结果如下
 1 // 立即执行
 2 // 等待2秒执行
 aa
 3
 
c#实用应用
- MD5加密 - 任何一个东西都可以用md5生成一个唯一不可逆固定长度的字符串密码,相同的东西md5密码都是一样的
 字符串生成md5
 string str = "aaabbbccc";
 StringBuilder result = new StringBuilder();
 using(MD5 sc = MD5.Create())
 {
 byte[] bytes = sc.ComputeHash(Encoding.UTF8.GetBytes(str));
 for(int i = 0; i < bytes.Length; i++)
 {
 result.Append(bytes[i].ToString("x2"));
 }
 }
 文件生成md5
 StringBuilder result = new StringBuilder();
 using(MD5 sc = MD5.Create())
 {
 using(FileStream fs = File.OpenRead(@"F:\学习实验区\c#\demo.txt"))
 {
 byte[] bytes = sc.ComputeHash(fs);
 for(int i = 0; i < bytes.Length; i++)
 {
 result.Append(bytes[i].ToString("x2"));
 }
 }
 }
 
- excel操作(使用NPOI,下载地址http://npoi.codeplex.com/) - 写入数据到excel文件 - IWorkbook Iwb = new HSSFWorkbook(); // 创建工作薄
 ISheet Is = Iwb.CreateSheet("TestSheet"); // 创建一个工作表
 IRow row = Is.CreateRow(0); // 创建第0行
 row.CreateCell(0).SetCellValue("yejiawei"); // 创建行的第0个单元格并写入值
 row.CreateCell(1).SetCellValue(CellType.Blank); // 创建空的单元格
 using(FileStream fs = File.OpenWrite("test.xlsx"))
 {
 Iwb.Write(fs); // 写入文件
 }
 - 读取excel - using(FileStream fs = File.OpenRead("test.xlsx"))
 {
 IWorkbook wk = new HSSFWorkbook(fs); // 将excel数据读取到wk中
 for(int i = 0; i < wk.NumberOfSheets; i++)
 {
 ISheet sheet = wk.GetSheetAt(i); // 获取工作表
 for(int j = 0; j <= sheet.LastRowNum; j++)
 {
 IRow row = sheet.GetRow(i); // 获取行
 for(int k = 0; k <= row.LastCellNum; k++)
 {
 ICell cell = row.GetCell(k); // 获取单元格
 Console.WriteLine(cell);
 }
 Console.WriteLine();
 }
 }
 }
 
- 中文转拼音 - 安装插件 - 下载地址https://www.microsoft.com/zh-cn/download/details.aspx?id=15251
 安装CHSPinYinConv.msi软件,根据安装路径将ChnCharInfo程序集添加到程序中来
 - 将中文转成拼音 - string str = "你好";
 StringBuilder sb = new StringBuilder();
 for(int i = 0; i < str.Length; i++)
 {
 ChineseChar cn = new ChineseChar(str[i]); // 将每一个中文字转成ChineseChar实例
 if(cn.Pinyins.Count > 0)
 {
 string py = cn.Pinyins[0]; // 获取中文对应的拼音
 sb.Append(py.Substring(0, py.Length - 1));
 }
 }
 Console.WriteLine(sb);
 
c# 实用精华知识点全解的更多相关文章
- [转载] Python数据类型知识点全解
		[转载] Python数据类型知识点全解 1.字符串 字符串常用功能 name = 'derek' print(name.capitalize()) #首字母大写 Derek print(name.c ... 
- js面试题知识点全解(一变量类型和计算)
		1.js中使用typeof能得到哪些类型 2.何时使用===和== 3.js中的内置函数 4.js变量按存储方式区分为哪些类型,并描述其特点 5.如何理解json 以下对这些问题的知识点做一些总结: ... 
- js面试题知识点全解(一原型和原型链1)
		1.如何准确判断一个变量是数组类型2.写一个原型链继承的例子3.描述new一个对象的过程4.zepto(或其他框架)源码中如何使用原型链知识点:1.构造函数2.构造函数-扩展3.原型规则和示例4.原型 ... 
- js面试题知识点全解(一作用域和闭包)
		问题: 1.说一下对变量提升的理解 2.说明this几种不同的使用场景 3.如何理解作用域 4.实际开发中闭包的应用 知识点: js没有块级作用域只有函数和全局作用域,如下代码: if(true){ ... 
- js面试题知识点全解(一作用域)
		问题: 1.说一下对变量提升的理解 2.说明this几种不同的使用场景 3.如何理解作用域 4.实际开发中闭包的应用 知识点: js没有块级作用域只有函数和全局作用域,如下代码: if(true){ ... 
- js面试题知识点全解(一原型和原型链)
		1.如何准确判断一个变量是数组类型2.写一个原型链继承的例子3.描述new一个对象的过程4.zepto(或其他框架)源码中如何使用原型链知识点:1.构造函数2.构造函数-扩展3.原型规则和示例4.原型 ... 
- js面试题知识点全解(一闭包)
		闭包使用场景:1.函数作为返回值,如下场景 function F1(){ var a = 100 //自由变量 //返回一个函数(函数作为返回值) return function(){ console ... 
- React基础知识点全解
		• propTypes.defaultProps 作为 properties 定义,也可以在组件外部通过键值对方式进行设置. • 设置组件初始的 state不支持 getIniti ... 
- TabLayout基本属性全解
		代码地址如下:http://www.demodashi.com/demo/14659.html 前言 之前讲过一篇TabLayout实现顶部导航的文章,这篇文章,来详细介绍下TabLayout的一些基 ... 
随机推荐
- 使用 grep 查找所有包含指定文本的文件
			目标:本文提供一些关于如何搜索出指定目录或整个文件系统中那些包含指定单词或字符串的文件. 难度:容易 约定: # - 需要使用 root 权限来执行指定命令,可以直接使用 root 用户来执行也可以使 ... 
- Email-Ext Plugin install ------ Jenkins Plugins
			一.基本信息 1. Email-Ext Plugin功能简介 支持Jenkins邮件发送时,自定义邮件内容功能.详情可以查看jenkins的wiki : https://wiki.jenkins-ci ... 
- R语言笔记002——sample()函数
			sample()函数 sample(x,size,replace=FALSE) x表示一个或多个向量,size表示从x中随机取的样本个数,replace=FALSE表示不放回抽样,即不会选取到相同的值 ... 
- HDU 5183 Negative and Positive (NP) (hashmap+YY)
			学到了以邻接表方式建立的hashmap 题意:给你一串数a和一个数k,都有正有负,问知否能找到一对数(i,j)(i<=j)保证a [i] - a [i+1] + a [i+2] - a [i+3 ... 
- mysqldump 用法汇总
			mysql mysqldump 只导出表结构 不导出数据 复制代码代码如下: mysqldump --opt -d 数据库名 -u root -p > xxx.sql 备份数据库 复制代码代 ... 
- Spring Cloud遇到的坑——服务状态为DOWN
			今天启动上次写好的微服务时出现了这样的情况: 于是一脸懵逼... 忽然打开DOWN状态微服务的pom文件,看到如下情况: <dependencies> <dependency> ... 
- RocketMQ原理讲解系列文章
			[RocketMQ原理解析][http://blog.csdn.net/quhongwei_zhanqiu/article/category/2548637] [消息的可靠性.顺序和重复][https ... 
- PowerDesigner(一)-PowerDesigner概述(系统分析与建模)
			PowerDesigner概述 PowerDesigner是Sybase公司推出的一个集成了企业架构,UML(统一建模语言)和数据库的CASE(计算机辅助软件工程)工具.它不仅可以用于系统设计和开发 ... 
- hdoj-1285-确定比赛名次(拓扑排序)
			题目链接 /* Name:hdoj-1285-确定比赛名次 Copyright: Author: Date: 2018/4/11 15:59:18 Description: 标准的拓扑排序模板题,注意 ... 
- VC6常用插件
			VC6常用插件 2009-10-09 17:27 1.Visual Assist(强烈推荐) http://www.wholetomato.com/ VA从5.0一直到现在的VAX,功能 ... 
