zoukankan      html  css  js  c++  java
  • c# 实用精华知识点全解

    本文介绍c#的实用知识点

    写在前面(通识)

    1. vs常用快捷键

      F5 调试运行程序
      ctrl F5 不调试运行程序
      F11 逐条语句调试
      F10 逐过程调试程序
      注释快捷键 ctrl + k + c
      代码格式化 ctrl + A + k + F
      强制智能提示 ctrl + J
      
    2. 面相对象语言三大特性

      封装性,重复代码共用
      继承性,类,接口等的继承
      多态性,不同的子类调用父类的方法,执行效果不一样
      
    3. c#中的访问修饰符

      private 本类内部可以使用
      protected 本类内部和子类内部可以使用
      internal 当前程序集中可用
      protected internal 当前程序集中,并且是的当前类和子类内部可用
      public 访问无限制
      类成员不写访问修饰符默认是private
      类不写访问修饰符默认是internal
      命名空间中定义的成员只能是public或者internal
      
    4. 属性和字段

      private string _str = "aaa"; // 字段
      internal int num { get; set; } // 属性
      
    5. 方法的重载

      方法名相同,只要参数类型、个数或者顺序不同时就认为是不同的函数
      
    6. 泛型

      泛型是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) { }
      
    7. 测量代码的运行时间

      Stopwatch watch = new Stopwatch();
      watch.Start();
      // ...
      watch.Stop();
      TimeSpan time = watch.Elapsed;
      
    8. 生成guid

      String str = Guid.NewGuid().ToString();
      
    9. 嵌套引号的写法

      string str = @"aaaa""aa""";
      
    10. 扩展方法

      指定任意一个顶级静态类就可以定义任意类型的扩展方法
      定义扩展方法
          public static class Demo
          {
              public static void Fn(this int a)
              {
                  Console.WriteLine("aa");
              }
          }
      使用扩展方法
          int num = 222;
          num.Fn();
      

    c#基础

    1. 变量

      声明变量

      声明变量 string str1 = 'aa', str2
      添加?号,表示可以赋值null,int? i = 1; 等价于 Nullable<int> a = null;
      

      成员变量

      static string str;
      string str1;
      public void Fn()
      {
          str = "aaa";
          str1 = "bbb";
      }
      

      局部变量

      在代码块中定义的变量,只在代码块中有效
      嵌套的子作用域中不能有父作用域中的同名变量
      
    2. 常量

      const string str2 = "aaa";
      在声明的时候必须赋值,并且后续无法修改
      
    3. 数据类型

      值类型

      整数类型
          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
      
    4. 表达式和运算符

      算数运算符 + - * / %
      赋值运算符 = += -= /= *= %=
      关系运算符 > < == >= <= !=
      逻辑运算符 && || ! & 
          && 当等式左边为false,不会再计算等式右边
          & 等式左右两边都会计算
      内置运算符
          is判断数据类型 bool test = 11 is object; 
          三元运算符 false ? 1 : 2;
          new运算符,创建实例
          typeof运算符,获取类型的类型,Type result = typeof(int);
      
    5. 流程控制语句

      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");
                  }
      
    6. 索引器

      索引器可以方便的访问类的成员
      声明索引器
          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#基础升级

    1. 数组(不可变)

      一维数组

      声明数组 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);
              }
      
    2. 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){} // 遍历
      
    3. 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; // 数组长度
      
    4. 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; // 值
          }
      
    5. 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) { }
      
    6. 方法参数

      一般传参
          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);
      
    7. 异常处理

      try
      {
          throw new Exception("aa");
      }catch(Exception ex)
      {
          // 捕获异常
          Console.WriteLine(ex.Message);
          throw; // 错误向方法的调用者抛出
      }
      finally
      {
          // 始终都会执行
      }
      
    8. 接口

      基本使用

      类只能继承一个抽象类,使用接口没有限制
      接口中只定义声明,子类实现这些声明,并且是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();
      }
      
    9. 迭代器

      迭代器就是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);
              }
      
    10. 文件流

      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#	est.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#	est.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);
              }
          }
      }
      
    11. 路径操作

      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();
      
    12. 序列化

      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;
      }
      
    13. 正则表达式

      元字符

      . -> 除了
      以外的任意单个字符
      [] -> 字符组,多个字符任意一个
      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", @"aa", "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 + "-";
      }
      
    14. 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...
      
    15. 反射

      反射的作用就是通过不导入程序集的方式,获取程序中的内容
      获取程序集 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" });
      
    16. 线程

      线程的使用

      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);
      
    17. 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实例
      }
      
    18. 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#实用应用

    1. 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"));
                  }
              }
          }
      
    2. 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();
              }
          }
      }
      
    3. 中文转拼音

      安装插件

      下载地址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);
      
  • 相关阅读:
    centos7 双网卡设置(先NAT和后桥接)
    centos7 nginx搭建及其反向代理
    centos7 出现please make your choice from 1 to enter..
    centos7 keepalive双机热备~
    多线程【转】
    多进程的基本使用--multiprocessing 【转】
    http--一次完整的HTTP事务是怎样一个过程?【转】
    【转】Python操作MongoDB
    文件操作
    Log4j 日志操作包配置详解
  • 原文地址:https://www.cnblogs.com/ye-hcj/p/8214566.html
Copyright © 2011-2022 走看看