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: Test1 where T: Test2 { }
        public interface Test1: Test2 { }
        public interface Test2 { }
    泛型方法 public void Fn(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 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 fn = (str) => { };
            public delegate void Dlg(T str);
        内置委托类型
            Action类型,没有返回值 Action Fn = (str) => { };
            Func类型,有返回值 Func 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 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 list = new List() { 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 obj = new Dictionary();
    添加成员 obj.Add("a", "aaa");
    访问成员 obj["a"];
    遍历成员
        根据键遍历 foreach(string item in obj.Keys) { }
        根据值遍历 foreach(string item in obj.Values) { }
        根据键值对遍历 foreach(KeyValuePair 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#\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);
            }
        }
    }
  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. 正则表达式

    元字符

    . -> 除了\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 + "-";
    }
  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 Fn(string str)
        {
            return await Fn1(str);
        }
        Task 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);

转载于:https://www.cnblogs.com/ye-hcj/p/8214566.html

你可能感兴趣的:(c# 实用精华知识点全解)