接口与委托

摘要:
在接口中可以声明方法、属性、索引指示器和事件,接口中并不提供它们的实现。因此接口是函数成员声明的集合。由于C#语言不支持多继承,因此,如果某个类需要继承多个类的行为时,只能使用多个接口加以说明。委托类型,在功能上它类似C语言的函数指针,目的是通过创建代表类型对象去调用函数。创建新类所依据的类称为父类或基类,新建的类称为子类。可以这么说,子类是父类的具体化,父类是子类的一般化。

在接口中可以声明方法、属性、索引指示器和事件,接口中并不提供它们的实现。因此接口是函数成员声明的集合。如果类或结构从一个接口派生,则这个类或结构负责实现该接口中所声明的所有函数成员。一个接口可以继承多个接口,而一个类或结构可以实现多个接口。由于C#语言不支持多继承,因此,如果某个类需要继承多个类的行为时,只能使用多个接口加以说明。

委托类型,在功能上它类似C语言的函数指针,目的是通过创建代表类型对象去调用函数。使用代表类型的第一步,是从delegate类派生出一个代表类型,指明这个代表类型对象要代表的函数的返回值类型,参数的个数及类型,因此C#中的代表类型是类型安全的。

一、继承

继承是允许重用现有类去创建新类的过程,使用继承的好处是我们无需从头开始创建新类,便可以在现有类的基础上添加新的属性、方法和事件。创建新类所依据的类称为父类或基类,新建的类称为子类。可以这么说,子类是父类的具体化,父类是子类的一般化。
在C#中,不支持多重继承,但可以借用接口这个概念来实现多重继承。
n 语法:
class 子类:父类{}
n 示例:
//父类 public class Person{
private string _name;
private uint _age;
public void GetInfo()
{
Console.WriteLine("请输入您的姓名和年龄");
_name = Console.ReadLine();
_age = uint.Parse(Console.ReadLine());
}
public void DispInfo()
{
Console.WriteLine("尊敬的 {0},您的年龄为 {1} ", _name, _age);
}
}
//派生类
public class Student:Person{
private string _school;
private uint _eng;
private uint _math;
private uint _sci;
public void GetMarks()
{
Console.WriteLine(“请输入学校名称");
_school = Console.ReadLine();
Console.WriteLine("请分别输入英语、数学和自然科学的分数。");
_eng = uint.Parse(Console.ReadLine());
_math = uint.Parse(Console.ReadLine());
_sci = uint.Parse(Console.ReadLine());
Console.WriteLine(“所得总分为:{0}",_eng+_math+_sci);
}
}
public class Exercise{
static void Main(string[] args){
Student objStudent = new Student();
objStudent.GetInfo();
objStudent.DispInfo();
objStudent.GetMarks();
}
}
n 说明:
Ø C#类始终继承一个基类(若未指定一个基类):Sytem.Object类
Ø 子类继承父类的所有成员(私有成员除外)
Ø 可以利用base关键字来访问基类成员和被重写的方法。
Ø 在创建子类实例时,可以用base来调用基类的构造函数,base只能访问基类的构造函数、实例方法或实例属性,不能访问基类的静态方法。
n 示例
public class Person
{
public string _name;
public uint _age;
public Person(string name, uint age)
{
this._name = name;
this._age = age;
Console.WriteLine(_name);
Console.WriteLine(_age);
}
}
public class Student:Person
{
private uint _id;
public Student(string name, uint age, uint id):base(name, age)
{
this._id = id;
Console.WriteLine(_id);
}
static void Main(string[] args)
{
//构造 Student
Student objStudent = new Student("XYZ", 45, 001);
}
}

二、方法重写

重写基类方法就是修改它的实现或者说在派生类中对它进行重新实现。
l 使用override关键字
用于修改方法, override修饰的方法是对基类中同名方法的新实现,基类中的同名方法必须声明为virtual或abstract类型。默认情况下,方法并非virtual方法,因此不能重写。基类和派生类同名方法的访问修饰符相同。
new、static和virtual不能与override同时修饰一个方法。
n 示例
Class Base
{
// 成员变量
int basevar;
// 成员函数
virtual void GetInfo()
{// 定义 }
}
Class Derived : Base
{
// 成员变量
int derivedvars;
// 成员函数
override void GetInfo()
{// 定义}
}
l 使用virtual关键字
用于将方法定义为多态。virtual修饰的方法称为虚拟方法,子类可以用override来自由实现各自版本的虚拟方法。
virtual不能与static、override同时修饰一个方法。
n 语法
[访问修饰符] virtual [返回类型] 方法名( [参数列表] )
{ ...
// Virtual 方法实现
...}
n 示例
class Employee
{
public virtual void EmpInfo()
{
Console.WriteLine(“此方法显示职员信息");
}
}
class DervEmployee: Employee
{
public override void EmpInfo()
{
base.EmpInfo();
Console.WriteLine(“此方法重写 base 方法");
}
}
static void Main(string[] args)
{
DervEmployee objDervEmployee = new DervEmployee();
objDervEmployee.EmpInfo();
Employee objEmployee = objDervEmployee;
objEmployee.EmpInfo();
}
l 关键字new
用于显式隐藏继承之基类的方法,即如果子类方法与父类方法同名,new会将派生类识别为一个全新的成员。new不能与override同时使用。

三、抽象类和抽象方法

不能实例化的类称为抽象类,抽象类是派生类的基础。通过不实现或部分实现,来创建模板,以派生子类。
l 定义
abstract class ClassOne
{//类实现}
l 说明
n 抽象类中可以同时含有抽象方法(以abstact修饰的方法,只存放原型,无具体实现)和非抽象方法。
n 派生类需实现基类的抽象方法(方法前应加override)。
l 示例1
using System;
namespace Example_5
{
abstract class ABC
{
public abstract void AFunc();
public void BFunc()
{
Console.WriteLine(“这是一个非抽象方法!");
}
}
class Derv : ABC
{
public override void AFunc()
{
Console.WriteLine(“这是一个抽象方法! ");
}
static void Main(string[] args)
{
Derv objB = new Derv();
objB.AFunc();
objB.BFunc();
}
}
}
l 示例2
abstract class MyAbs
{
public abstract void AbMethod();
}
//派生类
class MyClass : MyAbs
{
public override void AbMethod()
{
Console.WriteLine(“在 MyClass 中实现的抽象方法");
}
//派生自 MyClass 的子类
class SubMyClass:MyClass
{
public void General()
{
//未实现 AbMethod 抽象方法
Console.WriteLine("在 SubMyClass 中未实现的抽象方法 ");
}
}
四、接口
一个接口相当于一个抽象类,但比抽象类更抽象,它不能包含非抽象方法。接口的每个方法必须在派生类中实现。
接口的作用是提供一个模板,指明实现此特定接口的类必须实现该接口列出的所有成员。
l 定义
interface 接口名
, {
//只有方法声明,无实现
void method1();
int method2();
int method3(float);
}
l 说明
n 接口只限于对方法、索引器和属性的声明
n 接口中不能包含字段、构造函数和常量
n 接口的访问修饰符隐含为public,不能显式指定。
n 子类在实现接口中的方法时,不需要override关键字。
n 名称通常以I开头。
l 示例1:
public interface IPict
{
int DeleteImage();
void DisplayImage();
}
public class MyImages : IPict
{
//第一个方法的实现
public int DeleteImage()
{
Console.WriteLine(“DeleteImage 实现!");
return(5);
}
//第二个方法的实现
public void DisplayImage()
{
Console.Wr, iteLine("DisplayImage 实现!");
}
static void Main(string[] args)
{
MyImages objM = new MyImages();
objM.DisplayImage();
int t = objM.DeleteImage();
Console.WriteLine(t);
}
}
l 示例2:一个类既可以继承一个类,也可以实现接口,但这个基类必须先写入到基类列表中。
public class BaseIO
{
public void Open()
{
Console.WriteLine("BaseIO 的 Open 方法");
}
}
public interface IPict
{
int DeleteImage();
void DisplayImage();
}
public class MyImages : BaseIO, IPict
{
public int DeleteImage()
{
Console.WriteLine(“DeleteImage 实现!");
return(5);
}
public void DisplayImage()
{
Console.WriteLine(“DisplayImage 实现!");
}
void Main(string[] args){
MyImages objM = new MyImages();
objM.DisplayImage();
int val = objM.DeleteImage();
Console.WriteLine(val);
objM.Open();
}
}
l 多重接口实现:一个类不能继承多个类,但可以实现多个接口,如下例中的MyImages类。
public interface IPictManip
{void ApplyAlpha();}
//第二个接口
public interface IPict
{
int DeleteImage();
void DisplayImage();
}
public class BaseIO
{
public void Open()
{
Console.WriteLine(“BaseIO 的 Open 方法");
}
}
//一个类和两个接口的实现
public class MyImages:BaseIO,IPict, IPictManip
{
public int int DeleteImage()
{
Console.WriteLine(“DeleteIamge实现!”);
}
public void DisplayImage()
{
Console.WriteLine(“DisplayImage实现!”);
}
public void ApplyAlpha()
{
Console.WriteLine(“ApplyAlpha实现!”);
}
}
class Test
{
static void Main(string[] args)
{
MyImages objM = new MyImages();
objM.DisplayImage();
objM.DeleteImage();
objM.Open();
objM.ApplyAlpha();
}
}
l 显式接口实现
在 C# 中,只要不发生命名冲突,就完全可以允许多重接口实现,但如果两个接口中都有同一个方法签名,则应使用接口名来显式指定。
如:
public interface IPictManip
{
void ApplyAlpha();
void DisplayImage();
}
public interface IPict
{
int DeleteImage();
void DisplayImage();
}
public class BaseIO
{
public void Open()
{
Console.WriteLine(“BaseIO 的 Open 方法");
}
}
public class MyImages : BaseIO, IPict, IPictManip
{
public int DeleteImage()
{
Console.WriteLine(“DeleteImage 实现!");
return(5);
}
public void ApplyAlpha()
{
Console.WriteLine(“ApplyAlpha 实现!");
}
void IPict.DisplayImage()
{
Console.WriteLine(“DisplayImage 的 IPict 实现");
}
void IPictManip.DisplayImage()
{
Console.WriteLine(“DisplayImage 的 IPictManip 实现");
}
}
l 接口继承:C#中,允许一个接口有多个父接口,实现该接口的类必须实现所有接口中的抽象方法。
示例
public interface IPict
{int DeleteImage();}
public interface IPictManip
{
void ApplyAlpha();
void DisplayImage();
}
//继承多重接口
public interface IPictAll:IPict, IPictManip
{void ApplyBeta();}
public class MyImages:IPictAll
{
public int DeleteImage()
{
Console.WriteLine(“DeleteImage 实现!");
return(5);
}
public void ApplyAlpha()
{Console.WriteLine(“ApplyAlpha 实现!");}
public void ApplyBeta()
{Console.WriteLine(“ApplyBeta 实现!");}
public void DisplayImage()
{Console.WriteLine(“DisplayImage 实现!");}
static void Main(string[] args)
{
MyImages objM = new MyImages();
objM.DisplayImage();
int val = objM.DeleteImage();
Console.WriteLine(val);
objM.ApplyAlpha();
objM.ApplyBeta();
}
}
五、委托
使用委托可以在运行时动态设定要访问的方法,即使不知道方法名称,也可以调用方法,执行一个委托将执行该委托引用的方法。
l 定义委托
[访问修饰符] delegate 返回类型 委托名();
其定义与方法类似,但必须和方法具有相同的签名(参数相同、返回类型相同)。
l 实例委托
使其指向具体的方法。例如:
class Delegates
{public delegate int Call(int num1, int num2); //定义委托
class Math
{public int Multiply(int num1, int num2)
{// 实现}
public int Divide(int num1, int num2)
{// 实现}}
class TestDelegates
{static void Main()
{Call objCall;
Math objMath = new Math();
objCall = new Call(objMath.Multiply); //实例委托}}
l 调用委托
调用委托意味着使用委托对方法进行实例化。其形式与方法类似,只是调用委托是调用与委托关联的方法的实现代码。例如:
class Delegates
{// 委托定义
public delegate int Call(int num1, int num2); //定义委托
class Math
{// 乘法方法
public int Multiply(int num1, int num2)
{return num1*num2;}
// 除法方法
public int Divide(int num1, int num2)
{return num1/num2;}
}
static void Main(string[] args)
{// 委托的对象
Call objCall;
// Math 类的对象
Math objMath = new Math();
// 将方法与委托关联起来
objCall = new Call(objMath.Multiply); //实例委托
// 将委托实例化
int result = objCall(5, 3); //调用委托
System.Console.WriteLine("结果为 {0}", result);
}
}
六、事件
以电视节目上的抢答为例,主持人一开始宣布“请听题”,则参赛人会认真倾听主持人的问题。从程序员的角度来看,当听到“请听题”时,相当于触发了一个事件,告之参赛者应认真听题。在C#中,事件允许一个对象将发生的事件通知给其他对象。发出事件通知的称为发行者,对象可以订阅事件,该对象称为订阅者,一个事件可以有多个订阅者。
l 定义事件
[访问修饰符] event 委托名 事件名;如:
public delegate void delegateMe(); //定义委托
private event delegateMe eventMe; //定义一个事件
l 订阅事件
eventMe += new delegateMe(objA.Method); // objA、objB都订阅了事件eventMe
eventMe += new delegateMe(objB.Method);
l 引发事件:通知所有订阅该事件的对象
if(condition)
{eventMe();}
l 示例
class Delegate
{// 定义委托
public delegate void MeDelegate();
// 定义事
public event MeDelegate NotifyEveryOne;
public void Notify()
{// 如果事件不为 null
if(NotifyEveryOne != null)
{Console.WriteLine("触发事件:");
// 触发事件
NotifyEveryOne();
}
}
}
class ClassA
{
public void DispMethod()
{
Console.WriteLine(“Class A 已接到NotifyEveryOne 事件的通知!");
}
}
// 第二个类
class ClassB
{
public void DispMethod()
{
Console.WriteLine(“Class B 已接到NotifyEveryOne 事件的通知! ");
}
}
class TestEvents
{[STAThread]
static void Main(string[] args)
{// 委托的对象
Delegate objDelegate = new Delegate();
// ClassA 的对象
ClassA objClassA = new ClassA();
// ClassB 的对象
ClassB objClassB = new ClassB();
// 订阅该事件
objDelegate.NotifyEveryOne +=new Delegate.MeDelegate(objClassA.DispMethod);
objDelegate.NotifyEveryOne +=new Delegate.MeDelegate(objClassB.DispMethod);
objDelegate.Notify();
}
}

免责声明:文章转载自《接口与委托》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇「初级篇」跟我一起学docker(14)--docker swarm的使用【Unity Shader学习笔记】(一)在表面着色器中控制顶点变换下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

生成指定数量的假数据

实际上也不是什么正经需求,只是在画页面的时候需要放一些随机的假数据,且最好不要重复。我这里只放了十套假数据就懒得再放了,写成了一个方法先放在这里 随机生成一些假数据: private String getRandomInfo(String flag, int num){ List<String> list = null; int...

vsnprintf

http://www.cplusplus.com/reference/cstdio/vsnprintf/ int vsnprintf (char * s, size_t n, const char * format, va_list arg ); Write formatted data from variable argument list to siz...

各种电子面单-Api接口(顺丰、快递鸟、菜鸟)

目录 术语 电子面单样式 对接接口各家对比 各家合作流程对比 接口定义及说明 Request Params 系统级参数(公共参数) 接口参数 Response Params Java栗子 术语 对于一般人,电子面单的意思可能并不是很了解;说白了,就是快递员给你打印的快递单的电子版。 专业解释: 电子面单是一种通过热敏纸打印输出纸质物流面...

java基础知识--日期时间类

1.1 Date类  java.util.Date类 表示特定的瞬间,精确到毫秒。 继续查阅Date类的描述,发现Date拥有多个构造函数,只是部分已经过时,但是其中有未过时的构造函数可以把毫秒值转成日期对象。 public Date():分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。 public Date(long date)...

WPF MVVM模式

什么是MVVM模式,Model(模型)-View(视图)-ViewModel(视图模型) 先来讲MVC模式,模型-视图-控制器,相信大多数人都用过原理无非是: 页面产生某个请求,先找到页面对应的控制器,然后触发控制器的方法,控制器去模型调取数据拿回来,再返回给相应的视图,最后呈现页面。 MVVM模式原理类似MVC,只不过中间的不叫控制器了叫视图模型,功能也...

Scala日期处理

计算时间间隔  val d = new java.text.SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new java.util.Date()) val dateFormat = new java.text.SimpleDateFormat("yyyyMMdd HH:mm:ss")...