继承与组合方式复用
例:
static void Main(string[] args)
{
//B b = new B();
//A a = new A();
YZK y = new YZK();
y.Daren();
TuFei t = new TuFei();
t.LG = new LiGang();
t.Daren();
Console.ReadKey();
}
class LiGang
{
public void Daren()
{
Console.WriteLine("前勾拳");
Console.WriteLine("扫堂腿");
Console.WriteLine("九阴白骨爪");
}
public void Xiantanzi()
{
}
}
//继承方式实现复用
//只有父类的大部份行为、状态都需要的时候才继承
class YZK:LiGang
{
}
//组合方式实现复用
//组合方式没有继承的包袱,用的更多。
//一个类调用另一个类实现动作叫组合
class TuFei
{
public LiGang LG { get; set; }//类的属性,字段可以是另一个对象
public void Daren()
{
LG.Daren();//调用LG属性指向的对象的“daren”方法
}
}
class A
{
public A()
{
Console.WriteLine("A构造");
}
private void M1()
{
}
public void M2()
{
}
protected void M3()
{
}
//public A(int i)
//{
//}
}
class B : A
{
//public B(int i):base(1)
//{
//}
public B()//先调用父类的构造函数
{
Console.WriteLine("B构造");
base.M3();//调用父类的M3
this.M2();
//this.M1();//private成员只有自己能调用,儿子也不能调
this.M3();//只能儿子可以调
}
}
异常与异常处理
传统的错误表示方式:错误码。
需要知道不同错误码的含义,如果不处理错误码,则程序可能陷入不可以预置的错误。陈摄影师以为文件已经被删除造成的麻烦。
错误码的缺点:不处理则很难发现,每次处理则很麻烦;难以看出错误的原因;容易使得程序进入不确定状态。
try catch。Exception ex 异常也是对象。
Exception 类主要属性:Message、StackTrace
发生异常后程序默认就退出了,try代码块中的后续代码不会被执行。catch以后的代码则会继续执行。
不要吃掉异常,一般情况下不需要处理异常。 InnerException
扔出自己的异常,扔:throw,抓住:catch
VS中调试出现异常的时候如果想终止程序不要关界面,而是点击终止按钮。
例1:try…catch
static void Main(string[] args)
{
try
{
//抛出异常:throw exception
System.IO.File.Delete(@"D:\yichang.txt");
if (System.IO.File.Exists (@"D:\yichang.txt"))
{
System.IO.File.ReadAllLines (@"D:\yichang.txt");
}
//不要随意的try,catch,异常是“未考虑的情况”尽量不要靠try,catch来实现正常的逻辑,而是应该“读文件之前判断是否存在”
//用int.TryParse而不是Convery.ToInt32()
Console.WriteLine("删除成功");
}
//如果try括号中的代码发生异常,则catch中的代码会被执行
// catch (Exception ex)//抓住所有异常
catch (unauthorizedAccessException ex)//只抓unauthorizedAccessException异常
{
//unauthorizedAccessException
//所有异常信息对象的类都是直接或者间接从exception类继承
Console.WriteLine("删除失败,错误{0},堆栈{1}", ex.Message, ex.StackTrace);
}
catch (FileNotFoundException ex)
{
Console.WriteLine("删除的文件不存在");
}
//try的括号中的代码如果出现异常,则抛出异常的语句向下到try结束的代码都不会执行
//但是出了try的代码还是会执行
//System.IO.File.Delete(@"D:\yichang.txt");
System.IO.File.Delete("D:\\yichang.txt");
Console.WriteLine();
Console.ReadKey();
}
例2:try…finally
//尽量不要靠异常来判断执行逻辑,异常是一种“程序员代码错误导致的的情况”
//string s1 = "abc";
//int i;
//if (int.TryParse(s1, out i))
//{
// Console.WriteLine("成功");
//}
//else
//{
// Console.WriteLine("失败");
//}
//不推荐
//string s1 = "abc";
//try
//{
// Convert.ToInt32(s1);
// Console.WriteLine("成功");
//}
//catch (FormatException fex)
//{
// Console.WriteLine("失败");
//}
try
{
File.Delete(@"D:\yichang.exe");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message );
}
//可以try...catch..finally,也可以try..finally
finally//无论try中的代码是否执行,finally都会在try结束后执行finally中代码
{
Console.WriteLine("执行完成");
}
//如果没有catch异常,那么如果发生异常
//try后的代码不会执行,但finally会执行
//这就是在try后写代码和finally中写代码的区别
Console.WriteLine("2");
Console.ReadKey();
}
常量与静态成员
const常量。常量名要大写。一定不会变化的值才能声明为常量(全局变量)。
例:
class Program
{
//private const double PI = 3.14;//定义常量
//常量一般全部大写
public const double PI = 3.14;//定义常量
static void Main(string[] args)
{
//const double pi = 3.14;//定义常量
//pi = 2;//不能为常量赋值
Console.WriteLine(PI *PI );
Console.ReadKey();
}
static void M1()
{
Console.WriteLine(PI*2);
}
}
class A
{
void M1()
{
//因为常量对应任何的对象的值都不变,所有不需要通过对象来调用
//直接通过类名引用
double d1 = Math.PI;
double d= Program.PI * 3;
}
}
class B
{
public const double PI = 8.88;
}
}
static类变量。readonly。
不用new就能用的方法:static方法,static方法其实就是普通函数
在static成员中可以调用其他static成员,但是不能调用非static成员。
在非static成员中可以调用static成员。string的static成员和非static成员。
不需要记,分析是否有状态就行。
例:
static void Main(string[] args)
{
A a1 = new A();
a1.Age = 50;
A.F1 = 30;//引用静态成员的时侯直接“类名.成员名即可”
A a2 = new A();
a2.Age = 60;
A.F1 = 80;
Ou(a1);
Ou(a2);
M1();
Console.ReadKey();
}
static void Ou(A a)
{
Console.WriteLine(a.Age);
}
static void M1()
{
//F1起到全局变量的作用
Console.WriteLine(A.F1);
}
}
class A
{
//F1不和任何A的对象关联,对于A类只有这一份F1.
public static int F1;//静态变量(全局变量)
public int Age;
}
例2:
static void Main(string[] args)
{
A a = new A();
A.F1 = 50;
a.Hello();
A.M1();
//string s1 = "aaa";
//s1.Trim();
//string.Format();
//string.Join();
//Person.SayHello();
Person p1 = new Person();
p1.SayHello();
Person.Population = 999999;
Person.Report();
Console.ReadKey();
}
class Person
{
public static int Population;
public int Age;
public void SayHello()
{
Console.WriteLine(Age );
Report();
}
public static void Report()
{
//SayHello()
Console.WriteLine(Population );
}
}
class A
{
public static int F1 = 30;
private int F2;
//调用非static成员必须通过对象
public void Hello()
{
F1 = 10;//在对象中为一个不要求对象的成员
M1 ();
//this.M1();//不可以,因为this.调用的都是非static成员
}
static public void M1()
{
// A.Hello();
A a = new A();
a.Hello();
// Hello();//在static成员中不能直接调用非static成员
//F2 = 5;//因为static成员不要求对象,没有对象,所以不能直接调用
}
静态类,不能被new的类就是静态类。静态类一般用来实现一些函数库。***Helper,SqlHelper,PageHelper
sealed不能被继承。
例:
class Program
{
static void Main(string[] args)
{
//A a = new A();//静态类不能new
//Math.PI;
//string s = "";
//不能创建一个从String类继承的类,因为string是sealed
Console.ReadKey();
}
}
static class A
{
//静态类中不能声明非静态成员,木有意义
//private int Age;
}
sealed class B//sealed密闭类不能被继承,主要基于安全考虑
{
}
//class C : B
//{
//}
}
命名空间
namespace(命名空间),用于解决类重名问题,可以看做“类的文件夹”。
在代码中使用其他类的时候需要using类所在的namespace。System.Collections.ArrayList,快速引入的方法,右键→解析(Ctrl+.)。
“System.Collections”是命名空间(c:/temp/动作片/)," ArrayList"是类名(1.txt)
也可以直接引用类的全名。
为什么使用Convert、Console等类不需要自己写using?
如果代码和被使用的类在一个namespace则不需要using。
可以修改默认的namespace,因此不要认为在相同文件夹下就不用using,不在相同文件夹下就需要using。
命名空间不一定和文件夹结构、名称一致。易错:把cs移动到其他文件夹下不会自动更新namespace。
类内部声明类的引用。
说明:类的名字尽量不要和命名空间的名字重复,否则会有很多麻烦。
例:
namespace 命名空间
{
class Program
{
class Program
{
static void Main(string[] args)
{
Dog d1 = new Dog();//可以把类的namespace放到using中,就不用每次都通过Namespace来引用
//但是只有没有类名冲突才这么用,否则还是要用全名(类的全名:Namespace.类名)
//命名空间.test1.Dog d1 = new 命名空间.test1.Dog();
Cat cat = new Cat();//引用同namespace下的类,直接用
Person p1 = new Person();
//可以通过“namespace.类名”引用一个类
命名空间.test1.Person p2 = new 命名空间.test1.Person();
}
}
class Person
{
}
//class Person
//{
//}
namespace 命名空间
{
class Cat
{
}
}
namespace 命名空间.test1
{
class Person
{
}
}
namespace 命名空间.test1
{
class Dog
{
}
}
索引器
C#中提供了按照索引器进行访问的方法
定义索引器的方式:string this[int index]{get { return “”; }set { }},string为索引器的类型,[]中是参数列表。进行索引器写操作就是调用set代码块,在set内部使用value得到用户设置的值;进行读操作就执行get代码块。
索引器参数可以不止一个,类型也不限于int,几乎可以是任意类型。
程序员说要有属性,所以就有了属性。索引器同理。
索引器的本质,反编译之。
之前用到索引器的地方:string类char c = s1[2]。
索引器也可以只读,只要没有set段就可以了。
例:
static void Main(string[] args)
{
//int i = Add(1, 1);
//Console.WriteLine(i);
string s = “aaa”;
char ch = s[1];
Family f = new Family();
f[1] = “耳鸣”;
Console.WriteLine(f[“a”,true]);
Console.WriteLine(f[2]);
Console.ReadKey();
}
static int Add(int i1, int i2)
{
if (i1 == 1 && i2 == 1)
{
return 2;
}
//一旦抛出异常,就不存在“并非所有路径都有返回值的问题”
//异常抛出后续代码终止,返回值也就没有意义了
throw new Exception(“爷不干了”);
//return -1;
}
}
class Family
{
private string child1 = “大毛”;
private string child2 = “二毛”;
private string child3 = “五毛”;
public string this[int index]
{
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(“序号错误”);
}
}
}
public string this[string s,bool b]
{
get
{
return “”;
}
}
}