黑马程序员—C#系列 (三)

来源:互联网 发布:stata面板数据ols回归 编辑:程序博客网 时间:2024/05/16 02:20
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------

1.变量作用域

1) 变量的作用域是变量声明的最近一层的包着他的大括号
2) 两个函数之间无法访问各自内部定义的变量 
3) 如果需要则需要通过参数传递

2.面向对象(OOP,Object-Oriented programming)

面向对象概念
1) 面向对象的三个特性:封装、继承、多态
2) 类、对象:“人”是类,“张三”是“人”这个类的对象。类是抽象的,对象是具体的。按钮就是类,某个按钮就是对象。对象可以叫做类的实例(Instance)。类就像int,对象就像10
3) 字段Field(和某个对象相关的变量),字段就是类的状态(不同的对象可能不一样的状态就是字段)。人这个类有姓名、年龄、身高等字段。类不占内存,对象才占内存。字段描述对象特点的数据。眼睛的个数不能做为字段,因为所有人的眼睛个数都一样,没有差异性。
4) 方法Method(函数),方法就是类能够执行的动作,比如问好、吃饭等
5) 类的继承,类之间可以有继承关系,比如“电脑”类可以从“电器”类继承,这样的好处是“电脑”类只需要定义自己特有的字段、方法就可以,也就是只要定义内存大小、CPU型号这些字段或者弹出光驱等方法就可以。父类(Parent)、基类(Base,基业,祖宗十八代传下来的)。电脑类是电器类的子类(ChildClass)。重用。父类有的子类都有



class Person{ }
易错:类的定义中只能定义字段、方法等,不能直接写其他代码
一个类可有有多个实例,类就是把一系列相关的变量(状态)、行为定义为一个整体。字段记录的就是这个对象相关的数据。

访问级别
public(任何地方都可以访问);private(默认级别。只能由本类中的成员访问)。还有internal、protected两个级别
永远不要把字段public,字段一般都是private,字段开头小写
调用者只能通过方法来请求对象改变它的状态,是否改变,改变多少是类自己决定的。这是为什么字段不能public的原因

对象的引用(非常重要)
int、decimal、bool、byte、enum等基础类型(值类型)是传递拷贝;对象(引用类型)则是传递引用。因为基础类型不怎么占内存,而对象则比较占内存
i1=3;i2=i1;i1++;//i2是3
为对象变量重新赋值。p2=p1是让p2指向p1指向的对象,函数间传递普通的类的对象也是引用传递
p1=new Person();p1.i=3;p2=p1;p1.i++;//p2.i是4
p1.height = 180;//修改p1指向的对象的height字段的值为180
Person p1 = new Person();//new的操作相当于根据类的定义在内存中创建一块独立的区域//所以两个对象修改各自的字段不受影响
Person p1 = null;        //p1不指向任何的对象,//如果p1之前指向过对象,则切断p1和对象间的关系//以后如果碰到NullReferenceException,先看变量是不是指向了对象
值类型中,只有string可赋值为null,是个特例

属性
惯用法:属性开头字母大写,字段开头字母小写
    class Person     {        private int age;        public int Age        {            get{return age;}            set{age=value;}        }        public void SayHello()        {            Console.WriteLine("我的年龄是{0}",Age);        }    }
例子:限制非法值的设置
private string job;        public string Job //属性不会存储值,而是由相应的字段保存值        {            get            {                //当读取Job属性的时候执行的代码                return job;            }            set            {                //和使用字段相比,用属性可以拒绝非法值                if (value == "waitor")                {                    this.job = "大爷";//属性返回的值不一定非要存到私有字段中,怎么处理无所谓                    return;                }                this.job = value;//value是设置的值,名字是固定的                //当设置Job属性的时候执行的代码            }        }
1)只用set或者只用get就可以定义只读或者只写属性
2) 字段和属性的区别是什么?
属性看似字段、不是字段,可以进行非法值控制,可以设置只读。
3) Net3.x简化set、get:
public int Age{get;set;}
适合于set、get中没有特殊逻辑代码的情况。允许外部访问的值一定要声明为属性。
4) set、get块内部其实就是get_***、set_***方法。
5) 用简写方式不能只有get或者只有set。不合理   逻辑不对,报错

常见错误: 不要在类定义中写多行代码,多行代码必须定义在方法中,只能在声明字段等地方调用一个有返回值的一行代码。

构造函数
1) 构造函数用来创建对象,并且可以在构造函数中对对象进行初始化。
2) 构造函数是用来创建对象的特殊函数,函数名和类名一样,没有返回值,连void都不用。
3) 构造函数可以有参数,new对象的时候传递函数参数即可
4) 构造函数可以重载,也就是有多个参数不同的构造函数。
5) 如果不指定构造函数,则类有一个默认的无参构造函数。如果指定了构造函数,则不再有默认的无参构造函数,如果需要无参构造函数,则需要自己来写。
6) 构造函数的调用顺序(父子)
7) 当对象被创建的时候(new)构造函数被执行

继承
定义类的时候不指定父类,则父类是Object类。Object类是任何类的直接或者间接父类。所有类都是Object的子类
class Chinese : Person//: 后为父类的名字,一个类只能有一个父类
构造函数不能继承,它是用来初始化自己的,子类调用父类的构造函数初始化,不能继承,能继承的话就成为子类自己的了

对象的隐式转换和显式转换
父类的变量可以指向子类的变量  把子类的变量指向父类的变量就不成功,必须显式转
Chinese c2 = (Chinese)p1; //如果转换失败则抛异常
Chinese ch= new  Chinese();//隐式转换,把子类变量赋值给父类变量Person p = ch;//显式转换,把父类变量赋值给子类变量Person p = new Chinese();Chinese ch = (Chinese)p;//如果对象不在同一个继承树路径上//则不能强制类型转换Dog g = new Dog();Chinese ch = (Chinese)g;//错误

is运算 
is用来判断变量指向的对象是否是指定的类型或者指定类型子类类型
if(p is Chinese)//is运算符结果就是bool,表示是否是指定的类型。{ Console.WriteLine("中国人");}else if(p is Korean){ Console.WriteLine("韩国人");}

as 运算符
as可以起到判断类型和转换的双重作用
()转换和as 转换的区别:如果转换失败()会报异常,而as则会返回null
Chinese ch = p as Chinese ;if(ch!=null){  Console.WriteLine("中国人");}Korean ch = p as Korean ;if(ch!=null){   Console.WriteLine("韩国人");}
string s = new string("aaa") //创建了两个字符串对象,只要new就会创建一个新的字符串对象   先ToCharArry(),然后再创建一个"aaa"
父类没有无参的构造函数,子类必须显示显示调用父类的构造函数
子类不能调用父类私有方法。private成员只能自己调用,子类也不行。protect成员 只有自己和子类可以调用
new一个子类对象,首先会调用用父类的构造函数
    class A    {        public A(int i)        {            Console.WriteLine("A构造");        }        private void M1()        {        }        public void M2()        {            this.M3();        }        protected void M3()        {        }    }    class B : A    {        public B():base(1)//先调用父类的构造函数        {            base.M3();//调用父类的M3() 。            Console.WriteLine("B构造");            this.M2();            this.M3();//protected的,儿子可以调用            //this.M1(); //private成员只有自己能调用,儿子也不能调        }    }
类与类之间有 继承 和 组合  两种关系

继承方式实现复用,只有父类的大部分行为、状态都需要的时候才继承
组合方式实现复用,组合方式没有继承的包袱,用的更多。一个类调用另外一个类实现动作就叫组合
 组合例子:

    class Program    {        static void Main(string[] args)        {            YZK y = new YZK();            y.打人();            TuFei t = new TuFei();            t.LG = new LiGang();            t.打人();            //y.嫌摊子();            Console.ReadKey();        }    }   class LiGang    {        public void 打人()        {            Console.WriteLine("前勾拳");            Console.WriteLine("扫堂腿");            Console.WriteLine("九阴白骨爪");        }        public void 嫌摊子()        {        }    }    class YZK : LiGang    {    }    class TuFei    {        public LiGang LG { get; set; }//类的属性、字段可以是另外一个对象        public void 打人()        {            LG.打人();//调用LG属性指向的对象的“打人”方法        }    }

常量与静态成员
const常量:常量名要大写。一定不会变化的值才能声明为常量
static方法:不用new就能用的方法,static方法其实就是普通函数
在static成员中可以调用其他static成员,但是不能调用非static成员。
在非static成员中可以调用static成员。string的static成员和非static成员。不需要记,分析是否有状态就行
全局变量:static类变量,不用new一个对象就能调用,直接  类名.全局变量名 //A.F1 = 30;
引用静态成员的时候直接"类名.成员名即可"
静态类:不能被new的类就是静态类。静态类一般用来实现一些函数库。***Helper,SqlHelper,PageHelper   
static class A{ //静态类中不能声明非静态成员,木有意义!  //private int Age;} //A a = new A();//静态类不能new 
sealed(密闭类):不能被继承
sealed class B//sealed密闭类不能"被"继承,主要基于安全考虑{ }
面试题:不能创建一个从String类继承的类,因为String是sealed密闭类

例子:
 class A    {        public static int F1=30;        private int F2;        //调用非static成员必须通过对象        public void Hello()        {            F1 = 10;//在对象中为一个不要求对象的成员  赋值            M1();            A.M1();            //this.M1();//不可以,因为this.调用的都是非static成员        }        static public void M1()        {            //A.Hello();            //A a = new A();            //a.Hello();           // Hello();//在static成员中不能直接调用非static成员            //F2 = 5;//因为static成员不要求对象,没有对象,所以不能直接调用要求对象的非static成员        }    } 

命名空间
1)  namespace(命名空间),用于解决类重名问题,可以看做“类的文件夹”
2)  在代码中使用其他类的时候需要using类所在的namespace,但是只有没有类名冲突才这么用,否则还要用全名(类的全名:Namespace.类名)
System.Collections.ArrayList,快速引入的方法,右键→解析(Ctrl+.)。“System.Collections”是命名空间(c:/temp/动作片/)," ArrayList"是类名(1.txt)
3)  也可以直接引用类的全名
4)  如果代码和被使用的类在一个namespace则不需要using
5)  可以修改默认的namespace,因此不要认为在相同文件夹下就不用using,不在相同文件夹下就需要using
6)  命名空间不一定和文件夹结构、名称一致易错:把cs移动到其他文件夹下不会自动更新namespace
7)  说明:类的名字尽量不要和命名空间的名字重复,否则会有很多麻烦
8)  为什么使用Convert、Console等类不需要自己写using?using System;已经using过了

索引器
之前用到索引器的地方:
string类char c = s1[2]
定义索引器的方式:
string this[int index]{   get    {       return "";    }   set    {   }}//string为索引器的类型,[]中是参数列表。进行索引器写操作就是调用set代码块,在set内部使用value得到用户设置的值;进行读操作就执行get代码块
1)  索引器参数可以不止一个,类型也不限于int,几乎可以是任意类型
2)  程序员说要有属性,所以就有了属性。索引器同理
3)  索引器也可以只读,只要没有set段就可以了
        public string this[string s, bool b]        {            get            {                return "";            }        }
4)  索引器的本质,反编译看,也是和属性一样生成set_***,get_***,两个方法
5)  索引也是可以重载的
例子:
static void Main(string[] args)        {            string s = "aaa";            char ch = s[0];            Family f = new Family();            f[1] = "耳鸣";            Console.WriteLine(f["a", true]);            //Console.WriteLine(f[2]);            //Console.ReadKey();        }    class Family    {        private string child1="大毛";        private string child2 = "二毛";        private string child3 = "五毛";        public string this[int index]//索引器参数可以不止一个,类型也不限于int,几乎可以是任意类型。程序员说要有属性,所以就有了属性。索引器同理。        {            get            {                if (index == 0)                {                    return child1;                }                if (index == 1)                {                    return child2;                }                if (index == 2)                {                    return child3;                }                //自己也可以抛出异常,这里抛出的异常对象                //可以被catch抓住                throw new Exception("序号错误");            }            set            {                if (index == 0)                {                    child1 = value;                }                else if (index == 1)                {                    child2 = value;                }                else if (index == 2)                {                    child3 = value;                }                else                {                throw new Exception("序号错误");                }                            }        }
一旦抛出异常,就不存在“并非所有路径都返回值的问题”,异常抛出后续代码终止,返回值也就没有意义了

3.异常与异常处理 try catch

1)  Exception ex 异常也是对象
2)  Exception 是所有异常的父类,Exception 类主要属性:Message、StackTrace
3)  发生异常后程序默认就退出了,try代码块中的后续代码不会被执行。catch以后的代码则会继续执行
4)  不要吃掉异常,一般情况下不需要处理异常//VS中调试出现异常的时候如果想终止程序不要关界面,而是点击终止按钮。
5)  尽量不要靠异常来判断执行逻辑,异常是一种“程序员代码错误导致的情况”
            try            {                //抛出异常:throw exception                System.IO.File.Delete("c:\\sln20110305.exe");                if (System.IO.File.Exists("c:\\haha.txt"))                {                    System.IO.File.ReadAllLines("c:\\haha.txt");                }                //不要随意的try、catch,异常是“未考虑的情况”,尽量不要靠                //try catch来实现正常的逻辑,而是应该“读文件之前判断是否存在”                //用int.TryParse而不是Convert.ToInt32()                Console.WriteLine("删除exe成功");            }            //catch(Exception ex)//抓住所有的异常            catch (UnauthorizedAccessException ex)//只抓UnauthorizedAccessException异常            {                //UnauthorizedAccessException                //所有的异常信息对象的类都是直接或者间接从Exception类继承                Console.WriteLine("删除失败,错误{0},堆栈{1}",ex.Message, ex.StackTrace);            }            catch (FileNotFoundException ex)/可以写多个catch,/判断磁盘上文件是否存在            {                Console.WriteLine("要删除的文件不存在");            }
文件操作常用方法
System.IO.File.Delete(); System.IO.File.ReadAllLines();       System.IO.File.Exists();
可以try...catch...finally,也可以try...finally
           //无论try中的代码是否执行成功           //finally都会在try结束后执行finally中的代码            finally            {                Console.WriteLine("执行完成");                Console.ReadKey();            }            //如果没有catch异常,那么如果发生异常            //try后的代码不会执行,但是finally会执行            //这就是在try后写代码和finally中写代码的区别
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------