• 知识点


    走进了这个世界,但不能走的很远!

    第一章

    第二章

    第三章

    第四章

    第五章

    第六章

    第七章

    第八章:委托和事件

    第九章

    第十章

    第十一章

    第十二章

    第十三章

    第十四章

    第十五章

    第一章:

    1、.net Framework是什么?
        是一个平台,可以在这个平台上进行 开发、部署和执行应用程序。
    2、C#和.net什么关系?
        C#生成的代码是在.net环境中运行的,但是C#不是.net的一部分。
    3、C#生成的可执行程序特点和过程和C++生成程序的区别?
        从文件中的源代码到可执行的代码,两个过程:
        A:源代码编译成Microsoft中间语言(IL)
        B:CLR把中间语言(IL)编译成在平台(.net平台)上可以运行的代码,这各C++生成的可执行二进制代码(本地机器吗)有所不同
    4、CLR
        公共语言运行库,或者叫.net运行库。在CLR控制下运行的代码叫托管代码。是.net Framework的核心。CLR会检查哪些引用变量不再会访问了,然后会处理一下数据回收处理。

    第二章:

    1、为什么进行变量初始化?
        为了安全性考虑。
    2、初始化的两种情况?
        方法外的变量在没有显式初始化时,编译器会自动初始化。
        方法内的变量必须在使用前初始化,否则会出现错误,编译器不会自动初始化。例如:
                    int i;//
                Console.WriteLine(i);//会发生错误:    使用了未赋值的局部变量“i”
    3、类型推断?
        用var 声明变量时,变量类型会随着初始化时的值来推断出变量的类型,并且一旦初始化后此变量的类型也就推断出来并固定了。
    4、局部变量冲突
        在类级别和方法级别(暂且这样叫)声明的同名变量,不会引起冲突。
            class Program
        {
            private int i = 0;//类型级别
            static void Main(string[] args)
            {
                int i = 4;//方法级别
                Console.WriteLine(i);//输出4
            }
        }
    5、常量:
        const int i=9;
        #:常量是静态的,不用也不能用static来修饰;
            class Program
            {
                public const int i = 9;//类型级别
                static void Main(string[] args)
                {
                    Console.WriteLine(DDX.DD);//用类名来引用,说明是静态的
                    Console.Read();
                }
            }
            class DDX
            {
                public const int DD = 90;
            }
        #:常量一定在声明时初始化,下面是错误的
           const int i;
           i=9;
        #:常量 ,优点是能把数字表示成一个有意思的字符串  比如: const int RATE=0.80;是一个利率
    6、C#基本数据类型
        15种基本类型,其中有13种值类型,2种是引用类型。
    7、小技巧,Char类型字符的表示,比如'A'
        (Char)65  'u0041'  'x0041'
    8、一个特殊的引用string类型
                string str1 = "hello a";
                string str2 = str1;
                str2 += "b";
                Console.WriteLine(str1);//出现hello a
                Console.WriteLine(str2);//出现hello ab
            按正常的引用来思考:str1和str2是引用的同一个内存区域,str2的变量也会是str1的变化,但是str2变化后str1却没有变化,这是因为:修改一个字符串,就是再创建了一个全新的字符串对象。这是运算符重载的结果。
    9、@在字符串中的使用
        string s1="C:\1.txt";
        string s2=@"C:1.txt";
        @的作用就是把字符还当成原来的含义,比如“”就是一个普通斜线,但是@不能作用于双引号"。
    10、 switch case 语句注意点:
        case 后的表达式一定要是常量;
        case 后的语句为空时,就会接着执行下面的case语句,这样可以合并几个case
        switch(i)
        {
            case 0:
            case 1:
            case 2:
                Console.Write(i);//当是0,1,2时都会成立
                break;
            default :
                Do Something;
        }
        case 后一定要有 break;否则会出错,这是和C++不同的地方。
        case 中的两个或者常量不能有重复
        switch(i)
        {
            case 1:
            case 1:这样会出错的
        }
    11、 goto 语句的限制
        不能跑到循环内部;不能跳出类。
    12、枚举类型
        作用:存数据,一次能存在两种类型,并且可视化强,易懂
            class Program
        {
            public const int i = 9;//类型级别
            enum TT : int
            {
                Monday = 9,
                Tuesday,
                Thirday
            }
            static void Main(string[] args)
            {
                Console.WriteLine(Convert.ToInt32(TT.Monday));//9
                Console.WriteLine(TT.Monday.ToString());//Monday
                Console.Read();
            }
        }
    13、Main方法参数的使用 int Main(string[]args)
        在命令执行程序时,会使用的到
        int Main(string[] args)
        {
            for(int i=0;i<args.length;i++)
            {
                Console.WriteLine(args[i]);
            }
            Console.Read();
        }
        第二章部分.exe  23 34 eee bbb
        输出如下:
        23
        34
        eee
        bbb
    14、格式化输出字符
                    double a = 0.123;
                Console.WriteLine("{0:##.#0}", a);//输出.123
                Console.WriteLine("{0:##.#000}", a);//输出.1230,说明当0处有字符时,会用字符来代替掉0,但是如果0处没有字符时,还会显示0;说明当#处有字符时,也会被字符替换掉,但是当#处没有字符时,就不显示#;这是#和0当占位符用时的区别
    15、三个斜线注释的作用
        可以直接对一个方法或者类进行说明;设置VS--项目--属性--生成 选项卡里 选中生成XML文件;这样会在执行项目时生成XML格式的说明文件。
        T "表 示一个类型,F :"表示一个字段,"M∶ "表示一个成员
    16、预处理器指令
        作用:可以让一部分代码不会编译。这样,想生成一个程序的测试版本或者完全版本就有了用处。调试时也会用到。
        #define #undef #if #endif #elif #else   可以进行调试作用,
        #pragma 可以消除一些警告 例如字段定义后未使用会在编译时给出警告 这个警告的代号是169  ,#pragma warning disable   169 这样就消除了这种类型的警告;在发出警告或者错误提示时会在IDE中有行号显示,使用 #line 可以改变行号 比如:在第100行时出现错误 if(i=0),默认情况下系统会提示在100行的错误,但是在100行后使用 #line 101 "Class1.cs" 这时就会在错误时提示是在101行出现错误,如果想恢复原来的默认行号,可以使用#line default
        #warning "这里会出现一个警告" 会在出现#warning 处出现一个警告,警告的内容是后面的字符;
        #error "提示一个错误" 会在这里出现一个错误提示,编译不会再执行下去,停止了编译器的执行
        #region 与 #endregion 只是起到代码源文件中模块化的作用。
    17、一些标识符的规则,小技巧与常识
        一般情况下C#的关键字不用作标识符的,例如int string 等,但是加上@时可以用作标识符了,@string
                    string @int = "sss";
                Console.WriteLine(@int);//可以正常使用
        标识符也可以包含Unicode字符,比如u005f表示"_"下划线,_aa与u005faa都可以标识。

    第三章

    1、类成员的4种访问类型?
        internal public protected private
    2、类的常识:类的两个成员
        函数成员和数据成员;
        函数成员:方法、构造函数、析构函数、属性
        数据成员:字段,常量
    3、引用传递的好处
        按 引用传递的 效率更高,不用复制更多的副本,也就是少占据内存空间
    4、数组作为参数时是一种引用传递
    5、强迫值传递为引用传递, ref 和 out 关键字的使用,两者的区别?
    6、命名参数怎么用?可选参数的注意点?方法重载的几点要求?
    7、属性Get和Set代码段在什么时间会调用到?构造只读和只写属性怎么做?
        访问属性其实是间接与字段交互数据,这个字段是和对应的属性关联的。
                Age = 5;//其实执行的是age = value(5)+2;结果是7
                Console.WriteLine(age);
                int i = 0;
                i = age;//其实执行的是get里面的代码 i=age(0);结果是0,和想象的结果1不一样
                Console.WriteLine(i);
                private int age = 0;
                public int Age
                {
                    get
                    {
                        return age + 1;
                    }
                    set
                    {
                        age = value+2;
                    }
                }
    8、属性的自动实现
        如果属性的 set和 get访 问 器中 没有任何逻辑,就可以 使 用 自 动实现的 属性。
        public int Age{get;set;}不需要声明 private int age。 编译器会 自 动创建它。
        如果把属性名Age变成AGE或者aGE等呢?还没有尝试,在VS2005中会出错。
    9、静态构造函数
        与普通非静态构造函数不冲突,一个类中可以同时存在这两种构造函数。
        在什么时间执行?由.net库来执行,并且只最多执行一次,不确定的某个时间执行,可以确定的是在类引用前就会执行了。
        使用的原因?一些类中有一些静态字段,不能用普通的构造函数来初始化,所以要用静态的构造函数来初始化。
    10、构造函数间的调用和构造函数初始化器
        class A
        {
            public A():this("BBB")  //先执行有一个参数的构造函数,再执行第一个构造函数本身内的代码
            {
                Console.WriteLine("A");
            }
            public A(string s)
            {
                Console.WriteLine(s);
            }
        }
    11、只读字段与关键字readonly
        与 const 常量的区别:readonly是在执行时才知道其值, const 是在编译时就已经有了值;readonly可以赋值,但是只在构造函数中赋值一次, const 常量在定义时就要初始化。
    12、结构
        结构同样有构造函数,但是没有析构函数,是因为结构是值类型,初始化结构时可以像类那样用new关键字,但是也可以不用new,虽然使用了new,但是不会在堆上分配内存。
        结构的自定义的构造函数不能没有参数。
        在结构的内部不能直接为字段赋值。
        struct S
        {
            public S(int i)
            {
                this.i=i;
            }
            public int i=0;//这是操作是错误的,结构内部不能直接赋值给字段
        }
    13、类的拆分和关键字 partial
        在 class interface struct 等前面加上 partial关键字,在编译时编译器认为在不同文件中的同名 类/结构/接口 合并。
        文件1.cs中:
        partical class A
        {
            public int i=0;
        }
        文件2.cs中:
        partical class A
        {
            public int j=9;
        }
        其实两个类是一个类。这在WinForm程序中容易见到。
    14、静态类
        类关键字 class 前面 static ;
        不用再在类中的成员前面加关键字 static 了,所有成员都是静态的了。

    第四章:

    1、实现继承和接口继承:
        实现继承:一个派生类继承自基类;接口继承:派生类继承自接口。
        不支持多个实现继承,但是可以多个接口继承。
        结构的继承,只有接口继承。
    2、虚方法和虚属性
        除了构造函数和静态函数外,其他方法和属性都能声音为虚的,用关键字 virtual 来修饰。虚方法和属性可以在派生类中重写;
        重写时要用关键字 override 来修饰,C++中不需要使用 override 。

    3、隐藏方法
        基类中有方法fun();派生类中同样有相同签名的方法fun();那么在派生类中声明方法fun()时要使用 new :
        public new int fun();表示显式的说明,隐藏了基类的方法,如果不使用new的话,编译时会出现一个警告。隐藏方法没看出来会有什么实际意义 的作用。
    4、调用函数的基类版本。
        class father
        {
            public virtual void fun()
            {
                Console.WriteLine("father");
            }
        }
        class child:father
        {
            public override void fun()
            {
                Console.WriteLine("child");
                base.fun();//在派生类中重写基类的虚方法,如果想调用基类中的虚方法,可以使用base.[方法名]
            }
        }
    5、抽象函数和抽象类;
        抽象函数被 abstract 修饰,抽象函数是虚拟的,但不能用 virtual 修饰。
        抽象函数不能有代码,只能被子类中实现。
        如果函数被抽象了,也就是成为抽象函数,所在的类也必须也要被 abstract 修饰。此时类就成了抽象类。
        抽象函数 有点像是C++中的纯虚函数。
        抽象类中可以有普通函数。
        abstract class father
        {
            public abstract void fun();//只能在派生类中才有实现代码
        }
    6、密封函数和密封类:
        被 sealed 修饰的方法或者属性不能被派生类继承;被 sealed 修饰的类,表示类不能被继承。
    7、派生类和基类构造函数的调用顺序。
        class C
        {
            public C(string s)
            {
                Console.WriteLine(s);
            }
        }
        class D:C
        {
            public D():base("ccccc")//派生类的构造函数在被调用时,基类的构造函数会先被调用,调用方法是在派生类的构造函数后,使用base(实参数列表)
            {
                Console.WriteLine("D");
            }
        }
    8、继承时 private 修饰的数据成员和函数成员,不会在派生类中看到。
        class C
        {
            private string s = "abc";
            protected string s2 = "aaa";
            public string s3 = "bbb";
            public C(string s)
            {
                Console.WriteLine(s);
            }
        }
        class D:C
        {
            public D():base("ccccc")
            {
                Console.WriteLine("D");
            }
            public void fun()
            {
                Console.WriteLine(s);//出现错误,基类中private修饰的数据不会在派生类中被看到,protected public 可以被看到
            }
        }
    9、接口相关
        接口中不存在构造函数和字段。
        接口中的方法不能有实现代码。实现代码在派生类中,并且一定要实现。
        接口不能实例化。
        接口中的成员(方法)不能有修饰符 public private protected 等。因为里面的方法一定都是public类型的。
        接口之间可以继承。
    10、接口引用类。
        interface IFather
        {
        }
        class Child : IFather
        {
        }
        Main()
        {
            IFather [] arr=new IFather[2];
            arr[0]=new Child();
            arr[1]=new Child();
        }

    第五章:

    1、泛型类,泛型接口,泛型结构,泛型方法
        class teacher<T>
        {
            public T Name{ get;set};
            public void PrintName()
            {
                Console.WriteLine(name);
            }
        }
    2、默认值 default
        class Teacher<T>
        {
            public void Print()
            {
                T t = default(T);//函数级别的变量需要显式初始化,但是事先不知道T是值类型还是引用类型,所以要用default关键字来处理初始化。
                Console.WriteLine(t);
            }
        }
    3、约束
        class A
        {
        }
        class Teacher<T>  where T:A  //where中,约束格式,说明泛型类型T是类类型并且继承自A类,多个约束间用","隔开
        {
        }
        几种固定的约束:
        where T:struct //约束T为值类型
        where T:class //约束T一定是引用类型
        where T:IF //约束T继承接口IF
        where T:new() //约束T要有一个默认的构造函数
    4、泛型类的静态成员
        class Teacher<T>
        {
            public static int x;
        }
        Teacher<string>.x=9;
        Teacher<int>.x=90;
        Console.WriteLine(Teacher<string>.x);//结果是9,好像有多个静态成员
    5、协变与抗变(向上转型)
        class Base
        {
        }
        class child:Base
        {
        }
         Base b = new Child();//正常
         Child c = new Base();//不能通过编译
        基类的变量(b),可以引用子类的实例,因为所有的子类的都是基类的一种
        但是,子类的对象不能引用父类的实例
    6、泛型方法的定义和使用
        void swap<T>(ref T x,ref T y)
        {
            x=x+y;
        }
        调用
        int i=0;int j=9;swap<int>(i,j);
    7、泛型方法与约束
        void swap<T>(ref T x) where T:struct
        {
        }

    第六章:

    1、数组的初始化和赋值
        用一条语句初始化: int []arr = new int[3];  arr[1]=1;...
        用两条语句初始化: int []arr; arr = new int [3]; arr[1]=1;...
        初始化时进行赋值: int []arr = new int[3] {1,2,3};或者  int []arr = new int []{1,2,3};
        使用花括号初始化: int []arr = {1,2,3};
        注意:不论是在函数内还是在函数外,数组是引用类型,数组中的元素在没有显式赋值时,都是有初始的值,比如int类型数组,元素初始是0;
    2、锯齿数组
        int [][] arr = new int[3][];//3行数组,但是每一行的元素的个数还不确定
        arr[0] = new int[2]{1,2};//第一行有2 个元素
        arr[1] = new int[6];//第二行有6个元素
        arr[2] = new int[3];//第三行有3个元素

    锯齿数组的初始化一定要分两步进行!
    3、Array类
        是所有数组的基类;是一个抽像类。
        Array arr = Array.CreateInstance(typeof(int),3);
        int [] a = (int [])arr;
    4、数组的复制
        int [] a =new int[3];
                int[] b = new int[2] { 1,2};
                a = b;//这里的a是对b的引用,
                Console.WriteLine(b[1]);
                Console.WriteLine(a[1]);
                a[1] = 9;
                Console.WriteLine(b[1]);//和以前的不一样,变化为9,引用的一个表现。
                Console.WriteLine(a[3]);//出错,只有两个值
    5、元组
        数组中的每个元素都是相同的类型;元组中的每个元素的类型不一定相同。
    6、 yield 关键字的使用:yield return ; yield break ;
        预定义的集合类型中,可以使用 foreach 语句得到集合中的每个元素 例如List;
        当要自定义一个能使用 foreach 集合时,或者想在一个方法中返回很多数据,并且数据在一个集合中,以供别的程序foreach遍历时,就要使用到yeild关键字。
        IEnumerable GetA()
        {
            int i=0;
            while(i<100)
            {
                yield return i;    //使用了yield,返回 的值都会在IEnumerbale 对象中了,但是循环会接着执行。
                i++;
            }
        }

    第七章:

    1、++i和i++
        当占据一行时,会有相同的结果;
        当在表达式中时:
        int i=0;
        int a= i++;//结果   a=0;
        int b = ++i;//结果 b =1;
        结论:当它们用于较长的 表达式的内 部时,把运算符放在前面t++x,会在计算表达式之前递增 x,换言之,递增了x后,在表达式中使用新值进行计算。而把运算符放在后mtx++9会 在计算表达式之后递增 x-使 用 x的 原始值计算表达式
    2、溢出和处理 checked unchecked
        溢出的处理,
        byte i =255;
        i++;产生的溢出,默认情况下是不会检查的,为 unchecked
        如果代码块放在 checked 中
        checked
        (
            i=255;
            i++;
        )//会发出一个异常
    3、检测 对象或者变量是不是属于一个类型,或者属于一个类型的派生类型
        int i = 8;
        if(i is object)//is运算符的使用
        {}
    4、as运算符在类型转换中的使用
        object o1 = "stringss";//引用的是String类型的对象
        object o2 = new Hashmap();

        string s1=o1 as string;//s1赋值为string 类型的引用
        string s2=o2 as string;//s2会被赋值空null
        结论:如果对象名(o1)引用的内存数据("stringss")属于某个类型(string)或者其派生类型,则可以转换;否则结果是null.
    5、不安全代码中使用 sizeof
        sizeof(int);得到是int占据的长度。4个字节。
    6、可空类型:此值可以是基本的值,也可以是null
        int? a=null;//不会出现语法错误
        int? b=9;
        int? c= a+9;//c=null结果
        if(a>9){}//false
        结论:当与空数据进行运算时,只要有一个为null,结果就是null;在比较中特殊:两个进行比较的数据,只要有一个为null,结果是false;
    7、值类型和引用类型之间的转换:装箱和拆箱
        装箱:CLR为值在堆上分配一个临时的内存,保存装箱后的结果。
    8、运算符重载
        struct A
        {
            public int a,b;
            public static A operator +(A la,A ra)
            {
                A aresult;
                aresult.a = la.a+ra.a;
                aresult.b = la.b+ra.b;
                return aresult;
            }
        }
        注意:运算符重载定义时一定要使用 public  static operator 关键字。

    9、比较运算符重载时,要成对的重载,否则编译出错

      例如重载>=时也要同时重载<=;重载==时也要重载!=  等。

    10、自定义类型的强制类型转换

      pubic static implicit operator  float  (CurrenCy value) {return float值;}使用时是:float f = (float)crrrency;   implicit是指隐式转换,explicit是显式的

    第八章:

    ★、委托类型可以定义在类内,类外,也可以在名称空间中。

    ★、类型为***的委托,如delegate void INTO(); INTO into = new INTO(**);  类型为INTO的委托into.  委托实例 的实例化方法有至少三种方法

     1         delegate void PRINTF();
     2         static void Main(string[] args)
     3         {
     4             Program p = new Program();
     5             PRINTF printf = p.fun;//第一种实例化方法
     6            //PRINTF prinf = new PRINTF(p.fun);//第二种实例化方法
     7             //PRINTF prinf = delegate(){Console.WriteLine("00000")};//第三种实例化方法
     8             printf();//会调用两个方法的
     9             Console.Read();
    10         }
    11         public void fun()
    12         {
    13             Console.WriteLine("一个方法");
    14         }

    ★、调用委托的两种方法

     1         delegate void PRINTF();
     2         static void Main(string[] args)
     3         {
     4             Program p = new Program();
     5             PRINTF printf = new PRINTF(p.fun);
     6             //委托初始化后,两种等值的调用方法
     7             printf();
     8             printf.Invoke();
     9             Console.Read();
    10         }
    11         public void fun()
    12         {
    13             Console.WriteLine("委托的调用方法");
    14         }

    ★、可以使用静态方法和非静态方法初始化一个委托实例

    ★、一个委托中包含多个方法调用,叫多播委托。

     1         delegate void PRINTF();
     2         static void Main(string[] args)
     3         {
     4             Program p = new Program();
     5             PRINTF printf = new PRINTF(p.fun);
     6             printf += p.fun2;
     7             printf();//会调用两个方法的
     8             Console.Read();
     9         }
    10         public void fun()
    11         {
    12             Console.WriteLine("第一个方法");//一个问题,当这里有异常时,不会再往下调用方法了
    13         }
    14         public void fun2()
    15         {
    16             Console.WriteLine("第二个方法");
    17         }

    1、自定义委托和通用的两种委托
        一般使得的委托都是自定义委托,使用委托的示例:
        private delegate int MultiTwo(int i);
        int Func0(MultiTwo f,int b)
        {
           return f(b)+1;
        }
        int Add(int i)
        {
            return i+9;
        }
        main()
        {
            MultiTwo mt  = new MultiTwo(Add);
            Func0(mt,3);//委托可以作为函数的参数
        }
        通用的两种委托:Action<in T1,in T2> 此种委托有参数,但是没有返回值,T1和T2是传入的参数,这种委托的参数最多16个。
        Func<in T1,in T2,out Result>,有返回值的委托,最后一个参数是返回值的意思,并不会传入,也是最多16个参数。
        Func<int,int>  AFun = new Func<int,int>(Add);
        public void CreateInt(Func<int,int> action,int a)
        {
            int b = action(a);
        }
    2、匿名方法
        Func<int i,int j> F = delegate(int a)
        {
            return  a*2;
        }
        public delegate void PPint(string s);

        main()
        {
            PPint pp =  delegate(string s)
            {
                Console.WriteLine(s+"pp");
            }
            pp("dengdexin");//dengdexinpp
        }
    3、Lambda表达式的使用

      C# 3.0以后才会有此语法,当委托作为参数时,容易使用的到
        适用于匿名方法:
        int string con="aaaaa";
        Func<string a,string b,string c>  SPintf= (参数列表,和前面对应,这里是两个 ,如果只有一个参数的暑假,括号可以省略)=>
        {
            方法体,如果只有一句的话,可以不用{}括号。
                c=a+b;
               c=c+con;//这里表达式可以使用外部的变量。一个重要特点。

        return "ccc";
        }

      方法参数只有一个和多个的情况:只有一个时参数列表不用括号,多个时需要。

      方法中只有一条语句时,不用写{}和return ,编译器会做这个,例如:

     1 delegate int PRINTF(int a); 2

    3 PRINTF printf = a=>a * 2; 

      lambda表达式使用外部的变量时:编译器做了大量的工作,先是创建匿名类,再在类中添加字段,字段就是那些被调用的外部变量,同时用外部变量的值初始化此类,得到实例,再调用类的一个方法,也就是表达式块的方法部分。
    4、委托的另一个用处:事件
        事件基于委托。
        事件的两个基本关系者:发出者和侦听者;

     1     class Sender
     2     {
     3         public delegate void EventHandler(object o,EventArgs e);//定义委托
     4         public event EventHandler eventer;//定义事件eventer
     5         public void SendEvent()//触发事件
     6         {
     7             eventer(this,new EventArgs());
     8         }
     9     }
    10     class Listener
    11     {
    12         public void Handler(object o,EventArgs e)
    13         {
    14             Console.WriteLine("我接收并处理了消息");
    15         }
    16     }
    17     main()
    18     {
    19         Sender sender = new Sender();//一、创建事件触发者
    20         Listener listener = new Listener();//二、事件侦听者
    21         sender.eventer+=listener.Handler;//三、注册事件
    22     }

    第九章

    ★、System.String类型是.net 的类型,而string 才是C#语言的类型。

    ★、使用索引器的方式提取字符:

     1 string h = "hello"; 2 char c = h[4]; 

    1、String的一些劣势
        string str="hello";//假如想把每个字符用它后面的字符表示,以示加密:h->i;e->f;l->m;o->p;
         这时对每个字符的操作都会在内存中再开辟一段新的内存,以存在修改每个字符后的字符串,
         第一次 iello,开了一个内存
         第二次 ifllo,开了一个内存
         ...
         效率低下。
         StringBulid 不会出现这种问题,因为在使用StringBulid的对象时,第一个使用时会给定一定大小的内存,所有操作都是在这个内存中。
         当对字符串中的每个字符进行操作的时候,使用SB比较好一些。
    2、正则表达式。

    第十章:

    1、泛型类:List<T>
        初始化并设定初始值:
        List<int> intlist = new List<int>(){2,3};
        添加元素使用Add方法:
        intlist.Add(4);
        一次添加多个元素,使用AddRange方法:
        intlist.AddRange(5,6,7);
        插入元素Insert:
        intlist.Insert(2,8);
    2、队列
        先进先出(FIFO)
    3、栈
        后进先出
    4、链表
        优点:插入元素时会非常快,
        缺点:在查找后面的元素时,会慢。
    5、有序列表
        SortedList<Tkey,Tvalue>
    6、位数组
        BitArray
        每一个元素可以理解成一个Bool类型, BitArray ba = new BitArray(8);//设置长度为8,有代替多个Bool值的功效。
        BitVector32 是另一个位数组类,它和BitArrary不同在于,它是固定位数的,是32位,这算是它的一个缺点,但它的优点是数据元素存在栈上,运算速度 快。

    第十一章:

    1、什么是LINQ?
        语言集合查询,是用来访问数据的编程模型。个人的理解是有点像是SQL语句。
    2、
        int[] numbers = new int[] { 1, 3,5,7, 9, 11, 13, 15, 17,19};
        var even = from number in numbers
               where number % 3 == 0
               grouprby number descending
               select number;
        关键字:from in where groupby  select
    3、实现排序,查询等操作
    4、
    LINQ提供了Count()、Average()、Max()、Min()、Sum()等方法实现聚合查询。
    5、使用Skip()、SkipWhile()、Take()、TakeWhile()方法组合实现分区类查询

    第十二章:

    1、Dynamic Language Runtime
        是添加到CLR的一些服务,这些服务允许添加动态语言,
    2、Dynamic类型,和Var类型的比较
        Var:在运行时一旦初始化类型第一次后,以后就是这一类型,类型变固定了。
        Dynamic:在运行时可以随时改变表示的类型。
        动态变量引用的类型随时变化:
        main()
        {
            int i=9;
            Dynamic dyn = i;
            string str = "aaa";
            dyn = str;//这时又发生了变化。
        }
        Dynamic类型不会在编译时报错(就算有错也不会报)
        main()
        {
            Dyanmic dyn = new person();
            dyn.GetA(1,2,3);//引用了三个参数,和实际的一个参数的情况不相同,但在编译时不会报错,在运行时会报异常
        }
        class person
        {
            void GetA(int i)
            {
            }
        }

    第十三章

    1、下面的作用域
    {
        这里面的作用域叫块作用域或者结构作用域。
    }
    2、托管堆
        和普通的堆不同,它是在垃圾回收器的作用下工作的。
    3、托管资源和非托管资源?
        C#常见的非托管资源:文件旬柄、网 络连接和数据库连接;垃圾处理器不会处理非托管资源,因此需要手动实现。
        使用两种方法来翻译非托管资源:
        析构函数和实现 systemDisposable 接口。
    4、析构函数
         在垃圾回收器能处理托管资源时,当有析构函数时,会先执行析构函数。再执行垃圾回收器,第一次执行析构函数时不会清除对象,第二次会清除。
         C#中CLR会维护一个线程来执行析构函数,如果析构函数很多时 ,就会明显影响程序的性能。
         在C#中使用析构函数:
         ~MyClass(){}
         ;在方法体中对非托管资源进行释放。

      编译器做 了许多工作,编译器会把析构函数编译成对Finalize方法的调用

     1 protected override void Finalize()
     2 (
     3 try
     4 (
     5   // destructor  土 mp1ementation
     6 )
     7 finally
     8 (
     9   base.Fina1ize();
    10 )
    11 )


    5、实现Disposable接口。
        接口Disposable中有一个方法Dispose,可以在此方法中显式对非托管资源的释放。
        class MyClass : Disposable
        {
            private void Dispose()
            {
                //这里释放资源
            }
        }
        有些类的一些方法比如Close已经实现对方法Dispose的调用。
        using()子句也会自动调用Dispose来对非托管资源的释放。

    ★、析构函数和Disposable接口实现:两种释放非托管资源的方法

      析构函数,调用的时间不确定。

      Dispose方法,需要显式的调用。

      两种基质的同时使用能确保非托管资源的释放。

    ★、unsafe标记的内容

      1、标记方法,方法内可以使用指针等不安全代码

    unsafe int  Add()
    {
    //不安全代码
    }

      2、标记代码块,代码块内可以使用指针等不安全代码

    1 int Add()
    2 {
    3  unsafe
    4 {
    5 //不安全代码
    6 }   
    7 }

      3、标记类,类内部的任何方法中可以存在不安全代码

    1 unsafe class CC
    2 {
    3     //内部的任何方法可以存在不安全代码
    4 }

      4、标记字段,字段可以用指针类型

    1 class CC
    2 {
    3     unsafe int *pInt ;//指针
    4 }


    6、C#中使用指针
        使得指针的函数或者类要使用关键字unsafe,表示是不安全代码
        unsafe int GetPoint()
        {
            //使用指针
            int *p=null;
        }
        umsafe 关键字可以修饰变量和函数,还可以修饰类。但局部变量不能使用unsafe。
    7、不能存在指向类的指针,因为垃圾回收器不会维护关于指针的信息。
        class A
        {
            public long x;
            public long y;
        }
        A a=new A();
        long *pX = &(a.x);//出错
        原因:垃圾回收器会把对象(托管类型的成员)放到一个新单元上。
        处理方法:使用Fixed关键字,使用是告诉垃圾回收器,在Fixed块中的托管对象,这时可能会被指针用,不能移动。
        fixed(A a= new A())
        {
            long *pX = &(a.x);
        }
    8、stackalloc

       1 double * pDouble = stackalloc double[20]; 2 //在栈上分配20个double的内存 
        说明在栈上分配内存

    第十四章

    1、特性
        什么是特性?特性的分类?
        特性:其实质是一个类,并且此类继承自 System.Attribute 类。特性是提供有关编程元素(如类型、字段、方法和属性)的附加信息的描述性标记
        特性分为两种,一种是Microsoft定义好的,一种的我们自定义的。
        特性是作用:举一个例子,Dllimport特性,修饰一个方法时,是为了影响编译器,告诉编译器下面的方法是从某个DLL引用来的。

    ★、内部特性影响编译器的工作,自定义特性不会影响编译器

    ★、特性在编译好的程序集中是以元数据的形式存在的,可以通过反射读取这些元数据包含的信息
    2、如何自定义一个特性?
        [AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherted=false)]
        public class MySelfAttribute:Attribute
        {
            public MySelftAttribute(string str)//类可以有构造函数的,特性也是一种类的
            {}
        }
        这样就定义了一个特性。定义特性的说明:
        AttributeUage:这也是一个特性,是Microsoft定义好的一个特性。它为定义其他特性而生。
        AttributeTargets.Property:AttributeTargets,是一个枚举类型,Property只是其中的一个元素。在这里说明自定义的特性MySelfAttribute只能修饰属性Property。AttributeTargets还有很多元素,分别表示自定义的特性可以修饰类、方法等。
        AllowMultyple:是一个Bool类型,它表示自定义的属性MySelfAttribute是不是可以多次使用。为false表示只能使用一回。
        Inherted:表示自定义的属性在修改一个元数据(属性或者方法或者类等)时,当元数据被继承时,特性是不是也可以继承。
    3、如何使用自定义的特性?
        用特性来修饰一个类:
        [MySelf("aaaa")]//这里也可以用[MySelftAttribute("aaaa")]好像是使用构造函数来初始化一个实例一样。
        public class A
        {
        }
        但是修饰了一个类A后,有什么作用呢?

    ★、Type类 有许多派生类,和每个类型相对应;

    ★、得到每个类型的Type引用的三种方法

      Type t=typeof()   Type t=实例.GetType()   Type t=Type.GetType(实例所属类的完整类名)

    ★、Type类的实例很重要的用处是能得到某个类的各种成员信息(详细信息),
    4、Type类及其作用是什么?
        Type :是一个抽象类,不能用其构造函数来初始化一个实例,只能用其他方法。
        第一种:用 typeof            double d = 0.0;Type t = typeof(d);
        第二种:用GetType方法        double d = 0.0;Type t = d.GetType();
        第三种:用Type类的静态方法    Type t = Type.GetType(d);
        那么作用是什么呢?
        是根据一个类型的实例,比如d,得到这个实例d所对应的类型的各种信息,这些信息包括:
        实例对应类型的名字,在这里是System.Double;类型的成员有哪些,成员的名字是什么,成员的类型是方法还是字段;类型所在的命名空间等。详细见Type类。
    5、特性的使用?
        A:标识程序集
        程序集标识,三种特性与强名称(比如a.dll)来完整标识一个程序集。引用程序集时Assembly.Load(参数可以是程序集的区域特性和版本特性),这是特性的一个用处。简单的说,用特性来描述程序集后,可以被静态方法Load利用来得到程序集的实例。
        B:影响编译器,比如 [DllImport("User32.dll")] 的作用 。
    6、可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。
    namespace 反射
    {
        class Program
        {
            static void Main(string[] args)
            {
                /*******第一种反射表现:动态创建实例******/
                Assembly ass = Assembly.Load("反射");//加载程序集
                object o = ass.CreateInstance("反射.DD");//用完整的空间路径
                (o as DD).WriteString("呵呵");

                /******第二种表现:从现有对象获取类型并调用其方法*****/
                Type t = ass.GetType("反射.DD");
                MethodInfo mi = t.GetMethod("WriteString");
                mi.Invoke(o, new object[] {"嘿嘿" });


                Console.Read();
            }
        }
        public class DD
        {
            public void WriteString(string para)
            {
                Console.WriteLine("反射动态调用方法:"+para);
            }
        }
    }

    ★、特性是用来标记(类和方法等编程元素)的,反射是用来访问(特性和类等编程元素)的

    第十五章:

    1、结构
    try
    {
        if()
        {
            throw Exception1("1");
        }
        if()
        {
            throw Exception2("2");
        }
        ....
    }
    catch (Exception1 e)
    {
    }
    catch (Exception2 e)
    {
    }
    ....
    finally
    {
    }
    2、代码没有处理异常时的情况?
        当我们的代码没有处理异常时,应用程序会立即退出,并弹出一个对话框,运行程序时常见的错误。对话框中会表示出异常的详细信息。
    3、嵌套的try块。
        try
        {
            //这里的异常会在外部异常处理
            try
            {
                内异常,这里的异常会在内层异常中优先处理,再内部finally,再外部catch 再外部finally
            }
            catch (内层异常)
            {
            }
            finally
            {
                内层异常清理
            }
        }
        catch (外层异常)
        {
        }
        finally
        {
            外层异常清理
        }

     ★、执行步骤:

      (1)进入try块

      (2)如果try中没有错误,在try中执行完成后进行入finally块(如果存在的话);如果try中有错误,进入catch块,第(3)步。

      (3)在catch中处理错误,

      (4)在catch中处理错误结束后, 如果存在finally块,就进入finally块。

      (5)finally块中执行

      问题:

      1、try中存在并且可执行到return,还会进入finally吗?

      2、catch中有并且可执行到return的话,还会进入finally吗?

     ★有多个捕捉时,走进入最相关的catch,而不进入其他,包括兼容性的异常.

     1             try
     2             {
     3                 int zero = 0;
     4                 int i=10/zero;
     5             }
     6             catch (DivideByZeroException zeroexc)
     7             {
     8                 Console.WriteLine("zeroexc");//这里执行
     9             }
    10             catch(Exception ex)
    11             {
    12                 Console.WriteLine("exception");//这里不执行
    13             }

      ★、内层异常没有捕捉时,把异常抛给外层处理,并且在外层处理前先执行内部异常的finally块.

     1             try
     2             {
     3                 try
     4                 {
     5                     int zero = 0;
     6                     int i = 10 / zero;//内部异常没有捕捉,把异常抛给外层处理
     7                 }
     8                 finally
     9                 {
    10                     Console.WriteLine("finally");//先执行
    11                 }
    12             }
    13             catch (DivideByZeroException zeroexc)
    14             {
    15                 Console.WriteLine("zeroexc");//后执行
    16             }
  • 相关阅读:
    [oldboy-django][2深入django]老师管理--查看,添加,编辑
    全虚拟化和半虚拟化的区别 cpu的ring0~ring3又是什么概念?
    Ansible Jinja if 生成不同的MySQL文件
    Linux内核优化(未注释)
    CentOS7入门到精通实战课程课后习题
    基于sersync海量文件实时同步
    CentOS6系统优化
    lnmp架构实现动态php
    云计算与虚拟化KVM深度实践
    Linux6系统安装
  • 原文地址:https://www.cnblogs.com/ddx-deng/p/3805312.html
Copyright © 2020-2023  润新知