首页 > 代码库 > 知识点

知识点

第一章:

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 关键字。

第八章:

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是传入的参数。
    Func<in T1,in T2,out Result>,有返回值的委托,最后一个参数是返回值的意思,并不会传入。
    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表达式的使用
    适用于匿名方法:
    int string con="aaaaa";
    Func<string a,string b,string c>  SPintf= (参数列表,和前面对应,这里是两个 ,如果只有一个参数的暑假,括号可以省略)=>
    {
        方法体,如果只有一句的话,可以不用{}括号。
            c=a+b;
           c=c+con;//这里表达式可以使用外部的变量。一个重要特点。
    }
4、委托的另一个用处:事件
    事件基于委托。
    事件的两个基本关系者:发出者和侦听者;
    class Sender
    {
        public delegate void EventHandler(object o,EventArgs e);//定义委托
        public event EventHandler eventer;//定义事件eventer
        public void SendEvent()//触发事件
        {
            eventer(this,new EventArgs());
        }
    }
    class Listener
    {
        public void Handler(object o,EventArgs e)
        {
            Console.WriteLine("我接收并处理了消息");
        }
    }
    main()
    {
        Sender sender = new Sender();
        Listener listener = new Listener();
        sender.eventer+=listener.Handler;
    }

第九章:

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(){}
     ;在方法体中对非托管资源进行释放。
5、实现Disposable接口。
    接口Disposable中有一个方法Dispose,可以在此方法中显式对非托管资源的释放。
    class MyClass : Disposable
    {
        private void Dispose()
        {
            //这里释放资源
        }
    }
    有些类的一些方法比如Close已经实现对方法Dispose的调用。
    using()子句也会自动调用Dispose来对非托管资源的释放。
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、特性
    什么是特性?特性的分类?
    特性:其实质是一个类,并且此类继承自 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后,有什么作用呢?
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
    {
        外层异常清理
    }