C#编程简短总结
封装
field一般为private,定义的时候可以不赋值。不赋值的时候一般被构造函数初始化赋值,其值用来保存类实例的数据,可以被内部方法使用作为计算的数据来源。当需要继承类继承本类的时候,field要改为protected类型,这样继承类时子类可以对基类的field有完全访问权。
property一般为public,是向外暴露的窗口,属性可以为其他外部类使用。
方法可以是public的,用来向外暴露,外部可以直接调用。
继承
如果子类继承于父类,第一:子类拥有父类非private的属性和功能;第二:子类具有自己的属性和功能,即子类可以扩展父类没有的属性和功能;第三:子类还可以以自己的方式实现父类的功能(方法重写)。
基类的构造函数不可以被子类继承,只能被子类调用,调用父类的成员时可以用base关键字。注子类的构造方法需要调用父类同样参数类型的构造方法,用base关键字代表父类。注意先要set filed为protected
如果基类有两个构造函数:
public Animal () {};
public Animal (sring name) {}
子类构造函数的写法:
public Cat (): base() {}
public Cat () : base(name) {}
具体例子如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Animal.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Animal { protected string _name = ""; protected int _barkTime = 3; public int BarkTime { get { return _barkTime; } set { _barkTime = value; } } public Animal() { this._name = "无名氏"; } public Animal(string name) { _name = name; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Cat.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Cat : Animal { public Cat() : base() { } public Cat(string name) : base(name) { } public string Bark() { string result = ""; for (int i = 0; i < BarkTime; i++) { result += " 喵! "; } return "我的名字叫" + _name + result; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Dog.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Dog :Animal { public Dog() : base() { } public Dog(string name) : base(name) { } public string Bark() { string result = ""; for (int i = 0; i < BarkTime; i++) { result += " 汪! "; } return "我的名字叫" + _name + result; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
MainClass using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Cat myCat = new Cat("TuTu"); var feedback = myCat.Bark(); MessageBox.Show(feedback); } private void button2_Click(object sender, EventArgs e) { Dog myDog = new Dog("旺财"); myDog.BarkTime = 8; var feedback = myDog.Bark(); MessageBox.Show(feedback); } } }
多态和虚方法
第一:子类以父类的身份出现;第二:子类工作时以自己的方式来实现;第三:子类以父类的身份出现时,子类特有的属性和方法不可以使用。
为了使子类的实力完全接替来自父类的成员,父类必须将该成员声明为虚拟的(interface也是一种形式的虚拟)。这是通过在该成员的返回类型之前添加virtual关键字来实现。通常虚拟的是方法(虚方法还是可以有自己的方法体,实际做点事情),但除了字段不能虚拟,属性;事件;索引器都是可以虚拟的。子类可以选择override关键字,将父类的实现替换为自己的实现,这就是重写。
重构
上面的例子还是有一个部分比较冗余,就是每个动物都有一个Bark()方法,我们可以把这个方法提到基类去做。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Animal { protected string _name = ""; protected int _barkTime = 3; public int BarkTime { get { return _barkTime; } set { _barkTime = value; } } public Animal() { this._name = "无名氏"; } public Animal(string name) { _name = name; } public string Bark() { string result = ""; for (int i = 0; i < BarkTime; i++) { result += GetBarkSound() + ","; } return "我的名字叫" + _name + result; } public virtual string GetBarkSound() { return ""; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Cat : Animal { public Cat() : base() { } public Cat(string name) : base(name) { } public override string GetBarkSound() { return "喵"; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { class Dog :Animal { public Dog() : base() { } public Dog(string name) : base(name) { } public override string GetBarkSound() { return "汪"; } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private Animal[] _arrayAnimal; private void button1_Click(object sender, EventArgs e) { _arrayAnimal = new Animal[5]; _arrayAnimal[0] = new Cat("小花"); _arrayAnimal[1] = new Cat("阿毛"); _arrayAnimal[2] = new Dog("兔子"); _arrayAnimal[3] = new Cat("娇娇"); _arrayAnimal[4] = new Dog("汪汪"); } private void button2_Click(object sender, EventArgs e) { foreach (Animal item in _arrayAnimal) { MessageBox.Show(item.Bark()); } } } }
抽象类和抽象方法
在类前面加上abstract,方法public后加上abstract。抽象类提供一个继承的出发点,当设计一个新的抽象类时,一定是用来做继承之用。所以在一个以继承关系形成的等级结构里面,树叶节点应该是具体类。
注意:第一:抽象类的抽象方法不能写任何具体实现;第二:抽象方法是必须被子类重写的方法;第三:如果类中包含抽象方法,那么类就必须定义为抽象类,无论是否包含其他一般方法。
所以如果我们一开始就把Animal类设成抽象类,根本就没有必要存在虚方法的父类。
只是改下Animal.cs为:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WindowsFormsApplication1 { abstract class Animal { protected string _name = ""; protected int _barkTime = 3; public int BarkTime { get { return _barkTime; } set { _barkTime = value; } } public Animal() { this._name = "无名氏"; } public Animal(string name) { _name = name; } public string Bark() { string result = ""; for (int i = 0; i < BarkTime; i++) { result += GetBarkSound() + ","; } return "我的名字叫" + _name + result; } public abstract string GetBarkSound(); //注意这里一定不要写具体实现 } }
接口
接口内置有对属性和方法的简单声明(一样不可以声明任何成员的具体执行体),接口不能有构造函数和字段,不可以有修饰符,不能声明虚拟或者静态的。声明接口在语法上与声明抽象类完全相同。实现接口的类必须要实现接口的所有方法和属性。一个类可以支持多个接口,多个类也可以支持相同的接口。注意接口的命名在前面加一个大写的I。
同样是飞,鸟用翅膀飞,飞机用引擎飞,超人举起双手飞。若要把他们放在一起的话,用一个飞行行为的接口IFly来实现。
与抽象类的区别:
形态上:第一:抽象类可以给出一些成员的实现,接口不可以。第二:抽象类的抽象成员可以被子类部分实现,接口的成员需要实现类完全实现这些属性和方法。第三:一个类只能继承一个抽象类,但是可以实现多个接口。
继承关系上看:第一:类是对对象的抽象,所以抽象类是对对象的抽象(Animal),而接口是对行为的抽象(IFly)。
如果行为跨越不同类的对象用接口,对于一些相似类的对象用继承抽象类的方法。小猫,小狗,都是动物抽象类的子类,而飞机,麻雀,超人是完全不同种类的东西,用接口描述其共同能飞的特质。
一个类我们可以让其即继承一个基类同时又继承多个接口。
第三:抽象类是自底而上抽象出来的(从小猫小狗抽象到Animal类), 而接口则是自顶向下设计出来的(动物大会组织委员,并不知道谁来参加比赛,我只是预先设定了若干比赛项目,人来了根据自己的情况来选择参加的比赛)。
委托&事件
委托是对函数的封装,可以当作给要trigger的方法指定一个名称。而事件则是委托的一种特殊形式,当发生有意义的事件时,时间对象处理通知过程。委托是一种引用方法的类型,一旦委托分配了方法,委托将与该方法具有完全相同的行为,类和对象通过时间通知它们。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Cat { private string _name; public Cat(string name) { _name = name; } public delegate void CatShotEventHandler(); //声明CatShotEventHandler委托 public event CatShotEventHandler CatShout; //声明事件CatShout,后面没有(),它的类型是委托CatShotEventHandler public void Shout() //表明执行Shout()方法时,如果CatShout事件有新的委托登记方法,则按照注册顺序执行事件 { Console.WriteLine("喵,我是{0}", _name); if (CatShout != null) { CatShout(); //表示执行注册过的委托方法 } } } class Mouse { private string _name; public Mouse(string name) { _name = name; } public void Run() { Console.WriteLine("老猫来了,{0}快跑", _name); } } class Program { static void Main(string[] args) { Mouse mouse1 = new Mouse("Jerry"); Mouse mouse2 = new Mouse("Jack"); Cat cat = new Cat("Tom"); cat.CatShout += new Cat.CatShotEventHandler(mouse1.Run); //为事件登记一个新的委托方法 cat.CatShout += new Cat.CatShotEventHandler(mouse2.Run); //为事件登记另一个新的委托方法 cat.Shout(); Console.ReadLine(); } } }
这里new Cat.CatShotEventHandler(mouse1.Run);的含义实际就是实例化一个委托,而委托的实例其实就是Mouse的Run方法。+=表示增加一个需要触发事件时通知的对象。-=就是减少一个需要触发事件时通知的对象。
那么如何传递事件对象到委托方法里呢?用EventArgs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { public class CatShoutEventArgs : EventArgs { private string _name; public string Name //用一个public的property,表示CatShout事件触发时需要传递Cat对象的名字 { get { return _name; } set { _name = value; } } } class Cat { private string _name; public Cat(string name) { _name = name; } //声明委托CatShotEventHandler,此时委托所代表的方法不再是空的参数,而是有两个参数 public delegate void CatShotEventHandler(object sender, CatShoutEventArgs args); public event CatShotEventHandler CatShout; public void Shout() { Console.WriteLine("喵,我是{0}", _name); if (CatShout != null) { CatShoutEventArgs e = new CatShoutEventArgs() { Name = _name}; //因为CatShout是委托CatShotEventHandler的类型, //委托又是方法的注册,所以执行的时候要写两个参数 CatShout(this, e); } } } class Mouse { private string _name; public Mouse(string name) { _name = name; } public void Run(object sender, CatShoutEventArgs args) { Console.WriteLine("老猫{0}来了,{1}快跑", args.Name, _name); } } class Program { static void Main(string[] args) { Mouse mouse1 = new Mouse("Jerry"); Mouse mouse2 = new Mouse("Jack"); Cat cat = new Cat("Tom"); cat.CatShout += new Cat.CatShotEventHandler(mouse1.Run); //为事件登记一个新的委托方法 cat.CatShout += new Cat.CatShotEventHandler(mouse2.Run); //为事件登记另一个新的委托方法 cat.Shout(); Console.ReadLine(); } } }