1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > visual C#(十三)创建接口和定义抽象类

visual C#(十三)创建接口和定义抽象类

时间:2024-05-03 17:12:57

相关推荐

visual C#(十三)创建接口和定义抽象类

参考书:《 visual C# 从入门到精通》

第二部分 理解C#对象模型

第13章 创建接口和定义抽象类

文章目录

13.1 理解接口13.1.11 定义接口13.1.2 实现接口13.1.3 通过接口类引用类13.1.4 使用多个接口13.1.5 显式实现接口13.1.6 接口的限制13.1.7 定义和使用接口13.2 抽象类13.3 密封类13.3.1 密封方法13.3.2 实现并使用抽象类

接口不包含任何代码或数据,它只规定了从接口继承的类必须提供哪些方法和属性。所以继承真正强大的地方就在于能从接口继承。使用接口,方法的名称/签名可以和方法的具体实现完全隔绝。

抽象类很大程度上类似于接口,但他可以包含代码和数据。可以将抽象类中的某些方法指定为虚方法,且指定从抽象类继承的类必须以自己的方式实现这些方法。

13.1 理解接口

使用接口可以真正地将whathow区分开。接口指定-有什么,即指定方法的名称、返回类型和参数,具体-怎么做,如何实现就不是接口关心的。

13.1.11 定义接口

用关键字interface,接口中不允许使用任何访问修饰符:publicprivateprotected。如下:

interface IComparable{int CompareTo(object obj);}

接口不包含任何数据,不能向接口中添加任何字段。

13.1.2 实现接口

interface ILandBound{int NumberOfLegs();}class Horse:ILandBound{...;public int NumberOfLegs(){return 4;}}

实现接口时必须注意每个方法要与接口方法完全匹配:

方法名和放回类型完全匹配所有参数包括关键字refout都要完全匹配实现接口的所有方法都必须具有public可访问性。如果使用显式接口实现,就不应该为方法添加访问修饰符

一个类可以在从一个类继承的同时实现接口。C#根据位置来区分,基类名在前面,接口名在后面。

interface ILandBound{...;}class Mammal{...;}class Horse:Mammal,ILandBound{..;}

13.1.3 通过接口类引用类

我们知道基类变量能引用派生类对象,同样地接口变量也能引用实现该接口的类的对象。

Horse myHorse(...);ILandBound imyHorse=myHourse;

可以用is操作符来验证对象是实现了指定接口的一个类的实例。

if(myHorse is ILandBound){ILandBound iLandBoundAnimal=myHorse;}

13.1.4 使用多个接口

一个类只能有一个基类,但可以实现多个接口,没有数量限制。

class Horse:Mammal,ILandBound,IGrazable{...;}

13.1.5 显式实现接口

如果一个类实现多个接口,其中一些接口的方法的签名相同,C#并不能区分这个类的方法实现的式哪个接口的方法,这样的话就是一个方法同时实现了多个接口的方法。

为了能区分一个方法实现的是哪个接口的方法,就需要显式实现接口:

class Horse:ILandBound,IJourney{...;int ILandBound.NumberOfLegs(){return 4;}int IJourney.NumberOfLegs(){return 3;}}

注意到上述代码的一个细节:两个显式实现接口的方法都没有关键字public,实际上显式实现接口就不能用public,因为这两个方法对于类Horse来说是私有的。这样处理是合理的,如果是公有的话,类的对象访问方法是就没法确定调用的是哪个方法了,所以必须让它变为私有的 。

那么问题来了,我们要如何访问这两个方法呢?答案是要通过接口类引用Horse对象。

Horse horse=new Horse();...;IJourney journeyHorse=horse;int legsInJourney=journeyHorse.NumberOfLegs();ILandBound landBoundHorse=horse;int legsOnHorse=landBoundHorse.NumberOfLegs();

13.1.6 接口的限制

接口需要注意几点:

不能再接口中定义任何字段不能定义任何构造器不能定义任何析构器不能为任何方法指定访问修饰符不能再接口中嵌套任何类型一个接口可以从另一个接口继承,但不能从结构或类继承

13.1.7 定义和使用接口

下面我们运用学到的理论,创建一个简单的绘图应用程序,可以再画布上画出两种图形:鼠标左击画出正方形,右击画出圆形。

新建一个空白应用(通用Windows),先新建两个源文件定义两个接口:

IDraw.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI.Xaml.Controls;//手动添加namespace C_13_1_7{interface IDraw{void SetLocation(int xCoord, int yCoord);void Draw(Canvas canvas);}}

IColor.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI;namespace C_13_1_7{interface IColor{void SetColor(Color color);}}

然后新建两个源文件定义两个类

Square.cs

using System;using System.Collections.Generic;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Shapes;using Windows.UI.Xaml.Controls;namespace C_13_1_7{class Square:IDraw,IColor{private int sideLength;private int locX = 0, locY = 0;private Windows.UI.Xaml.Shapes.Rectangle rect = null;public Square(int sideLength){this.sideLength = sideLength;}void IDraw.Draw(Canvas canvas){if (this.rect != null)canvas.Children.Remove(this.rect);elsethis.rect = new Windows.UI.Xaml.Shapes.Rectangle();this.rect.Height = this.sideLength;this.rect.Width = this.sideLength;Canvas.SetTop(this.rect, this.locY);Canvas.SetLeft(this.rect, this.locX);canvas.Children.Add(this.rect);}void IColor.SetColor(Windows.UI.Color color){if (this.rect != null){SolidColorBrush brush = new SolidColorBrush(color);this.rect.Fill = brush;}}void IDraw.SetLocation(int xCoord, int yCoord){this.locX=xCoord;this.locY = yCoord;}}}

Circle.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Shapes;using Windows.UI.Xaml.Controls;namespace C_13_1_7{class Circle:IDraw,IColor{private int diameter;private int locX = 0, locY = 0;private Ellipse circle = null;public Circle(int diameter){this.diameter = diameter;}void IDraw.Draw(Canvas canvas){if (this.circle != null)canvas.Children.Remove(this.circle);elsethis.circle = new Ellipse();this.circle.Height = this.diameter;this.circle.Width = this.diameter;Canvas.SetTop(this.circle, this.locY);Canvas.SetLeft(this.circle, this.locX);canvas.Children.Add(this.circle);}void IColor.SetColor(Color color){if (circle != null){SolidColorBrush brush = new SolidColorBrush(color);this.circle.Fill = brush;}}void IDraw.SetLocation(int xCoord, int yCoord){this.locX=xCoord;this.locY = yCoord;}}}

然后再设计窗口下建立如下图布局,其实就是拖入两个控件:TextBlockCanvasCanvas控件可以就命名为draw,在Canvas的事件关联中关联两个事件:Trapped事件的处理方法命名为’drawingCavas_Tapped’、RightTapped的处理方法命名为draw_RightTapped。这两个方法的实现如下:

MainPage.xaml.cs

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Runtime.InteropServices.WindowsRuntime;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.UI;// /fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板namespace C_13_1_7{/// <summary>/// 可用于自身或导航至 Frame 内部的空白页。/// </summary>public sealed partial class MainPage : Page{public MainPage(){this.InitializeComponent();}private void drawingCavas_Tapped(object sender, TappedRoutedEventArgs e){Point mouseLocation = e.GetPosition(this.draw);Square mySquare = new Square(100);if(mySquare is IDraw){IDraw drawSquare = mySquare;drawSquare.SetLocation((int)mouseLocation.X, (int)mouseLocation.Y);drawSquare.Draw(draw);}if(mySquare is IColor){IColor colorSquare = mySquare;colorSquare.SetColor(Colors.BlueViolet);}}private void draw_RightTapped(object sender, RightTappedRoutedEventArgs e){Point mouseLocation = e.GetPosition(this.draw);Circle myCircle = new Circle(100);if(myCircle is IDraw){IDraw drawCircle = myCircle;drawCircle.SetLocation((int)mouseLocation.X, (int)mouseLocation.Y);drawCircle.Draw(draw);}if(myCircle is IColor){IColor colorCircle = myCircle;colorCircle.SetColor(Colors.HotPink);}}}}

完成以后直接可以运行了,效果如下:

这个画图程序看起来有点复杂只是因为其中运用了画图相关的指令我们很陌生,实际上回过头看看也没有很复杂,其中包括两个类一个实现画正方形一个画圆形,这两个类都实现了两个接口,意味着这两个类都必定包含两个接口中的方法。且实现接口的方法都是显式实现的,所以最后调用相关方法时需要事先用接口的实例引用两个类的对象。

这种风格的编程给人感觉好像有点啰嗦,想想我们完全可以不用接口来实现这个画图应用的,但这种做法还是有好处的,就是这样显得条理清晰,没那么容易出错,出错了也方便修改。

13.2 抽象类

通过将一个类显式声明为抽象类,明确不能创建这个类的实例。用关键字abstract来实现抽象类的声明。

abstract class GrazingMammal::Mammal,IGrazable{public abstruct void DigestGrass();...;}

抽象类可以包含抽象方法,抽象方法与虚方法相似,但它不含方法主体,派生类必须重写该方法。抽象方法不可以私有。

13.3 密封类

如果不希望一个类作为基类使用,可以用关键字sealed防止类被用作基类。

sealed class Horse::GrazingMammal,ILandBound{...;}

这样任何视图将它作为基类的代码都会编译出错。密封类中不能声明任何虚方法,同时抽象类不能密封。

13.3.1 密封方法

可以用sealed来声明一个非密封类中的一个单独的方法是密封的,这样派生类不能重写该方法。注意只有用override声明的方法才能密封,所以方法要声明为sealed override

区分下面四个关键字:

interface引入方法的名字virtual是方法的第一个实现override是方法的另一个实现sealed是方法的最后一个实现

13.3.2 实现并使用抽象类

现在我们考虑用抽象类来重新实现前面的画图程序,前面的画图程序是用了接口,但其实用抽象类可能更好一点。抽象类的话,直接可以把一些字段包括进去,同时建立三个抽象方法,这些方法是可以实现的,后面的派生类就重载这些方法的时候可以用base直接调用抽象类中定义的方法,还是要方便很多的。

首先是抽象方法:DrawShape.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;//手动添加using Windows.UI;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Shapes;using Windows.UI.Xaml.Controls;namespace C_13_1_7{abstract class DrawShape{private int size;private int locX = 0, locY = 0;protected Shape shape = null;public DrawShape(int size){this.size = size;}public void SetLocation(int xCoord,int yCoord){this.locX = xCoord;this.locY = yCoord;}public void SetColor(Color color){if (shape != null){SolidColorBrush brush = new SolidColorBrush(color);this.shape.Fill = brush;}}public virtual void Draw(Canvas canvas){if (this.shape == null){throw new InvalidOperationException("Shape is null");}this.shape.Height = this.size;this.shape.Width = this.size;Canvas.SetTop(this.shape, this.locY);Canvas.SetLeft(this.shape, this.locX);canvas.Children.Add(this.shape);}}}

然后两个派生类都要做相应的修改:

Square.cs

using System;using System.Collections.Generic;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Shapes;using Windows.UI.Xaml.Controls;namespace C_13_1_7{class Square : DrawShape{public Square(int sideLength) : base(sideLength){}public override void Draw(Canvas canvas){if (this.shape != null){canvas.Children.Remove(this.shape);}else{this.shape = new Windows.UI.Xaml.Shapes.Rectangle();}base.Draw(canvas);}}}

Circle.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.UI;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Shapes;using Windows.UI.Xaml.Controls;namespace C_13_1_7{class Circle:DrawShape{public Circle(int diameter) : base(diameter){}public override void Draw(Canvas canvas){if (this.shape != null){canvas.Children.Remove(this.shape);}else{this.shape = new Ellipse();}base.Draw(canvas);}}}

最后MainPage.xmal.cs只需做少量修改就可以了

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Runtime.InteropServices.WindowsRuntime;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.UI;// /fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板namespace C_13_1_7{/// <summary>/// 可用于自身或导航至 Frame 内部的空白页。/// </summary>public sealed partial class MainPage : Page{public MainPage(){this.InitializeComponent();}private void drawingCavas_Tapped(object sender, TappedRoutedEventArgs e){Point mouseLocation = e.GetPosition(this.draw);Square mySquare = new Square(100);mySquare.SetLocation((int)mouseLocation.X, (int)mouseLocation.Y);mySquare.Draw(draw);mySquare.SetColor(Colors.BlueViolet);}private void draw_RightTapped(object sender, RightTappedRoutedEventArgs e){Point mouseLocation = e.GetPosition(this.draw);Circle myCircle = new Circle(100);myCircle.SetLocation((int)mouseLocation.X, (int)mouseLocation.Y);myCircle.Draw(draw);myCircle.SetColor(Colors.HotPink);}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。