第十五章 接口
- 接口:它只是声明了一组函数成员而没有实现,接口的成员只能在类或结构中实现,接口可以帮助我们处理不同结构的类,虽然不同的类具有不同的结构(字段或者方法),但是接口为它们提供了统一的方法,可以让不同结构的类通过这些方法实现自己的功能。
- 接口不允许声明数据成员和静态成员,可以在接口中声明方法、属性、事件和索引器。
- 接口和接口成员的访问修饰符是不同的,接口可以使用任何形式的访问修饰符如public、internal、protected、private,而接口的成员是隐式的public,不允许有访问修饰符,即便是public也不行。
- 接口使用方法示例:
interface IInfo //声明接口
{
string GetName(); //只声明方法,没有实现部分
string GetAge();
}
class CA : IInfo //声明实现接口的CA类
{
public string Name;
public int Age;
public string GetName (){return Name;} //在CA类中实现接口的方法
public string GetAge(){return Age.ToString();}
}
class CB : IInfo //声明了实现接口的CB类
{
public string First;
public string Last;
public double PersonsAge;
public string GetName(){return First + " " + Last;}
public string GetAge(){return PersonsAge.ToString();}
}
class Program
{
static void PrintInfo(IInfo item) //传入接口的引用
{
Console.WriteLine("Name:{0},Age:{1}",item.GetName(),item.GetAge());
}
static void Main()
{
CA a = new CA(){Name = "workharding",Age = 25};
CB b = new CB(){First = "jone",Last = "jon",PersonsAge = 18};
PrintInfo(a); //对象的引用自动转换为它们实现的接口的引用
PrintInfo(b);
}
}
执行结果:
- Sort方法对整型数组元素排序很有效,但对类的对象不怎么管用,原因在于整型数组使用IComparable接口,而类没有直接使用它所以不能用,IComparable接口的声明为
public interface IComparable{int CompareTo(object obj);}
只有一个方法声明,如果类对象想使用Sort方法,需要在类中实现IComparable接口的成员。 - 示例:
class Myclass : IComparable //类实现引用
{
public int TheValue;
public int CompareTo(object obj) //实现方法
{
Myclass mc =(Myclass)obj;
if(this.TheValue>mc.TheValue) return 1; //当前的值大于参数的值,返回正数
if(this.TheValue<mc.TheValue) return -1;
return 0;
}
}
class Program
{
static void PrintOut(string s,Myclass[] mc)
{
Console.WriteLine(s);
foreach(var m in mc)
Console.WriteLine("{0}",m.TheValue);
Console.WriteLine(" ");
}
static void Main()
{
var myInt = new []{25,64,89,36,56};
Myclass[] mcArr = new Myclass[5]; //创建Myclass对象的数组
for(int i =0;i<5;i++)
{
mcArr[i] = new Myclass();
mcArr[i].TheValue = myInt[i];
}
PrintOut("Initial Order: ",mcArr );
Array.Sort(mcArr);
PrintOut("Sorted Order: ",mcArr );
}
}
执行结果:
- 声明接口:通过上述示例,大致明白了声明接口的过程,需要有关键字interface,接口名必须以大写I开头。
- 实现接口:格式是类名:接口名,若有多个接口,之间用逗号隔开,若是派生类,则基类必须在接口之前,还是以逗号间隔,接口成员的实现必须在类中。
- 简单接口示例:
//简单接口
using System;
namespace test24
{
interface IIfc1
{
void PrintOut(string s);
}
class Myclass : IIfc1
{
public void PrintOut(string s)
{
Console.WriteLine("Calling through: {0}",s);
}
}
class Program
{
static void Main(string[] args)
{
Myclass mc = new Myclass();
mc.PrintOut("hello everyone!");
}
}
}
结果显示“Calling through: hello everyone!”
- 接口是引用类型:我们不能直接通过类对象成员访问接口,我们可以把类对象引用强制转换为接口类型来获取接口的引用,通过接口应用,可以调用接口的方法。
- 接口引用类型示例:
interface IIfc1
{
void PrintOut(string s);
}
class Myclass:IIfc1 //实现接口
{
public void PrintOut(string s) //实现接口成员
{
Console.WriteLine("Calling through: {0}",s);
}
}
class Program
{
static void Main()
{
Myclass mc = new Myclass(); //创建类对象
mc.PrintOut("more hardworking,more luckier");
IIfc1 fc = (IIfc1)mc; //将类对象的引用强制转换为接口引用
fc.PrintOut("加油");
}
}
执行结果:
- 接口与as运算符:如果我们把类对象的引用强制转换为没有实现的接口的引用,会引发异常,而如果使用as运算符,则不会引发异常。as运算符如强制类型转换,只是不会抛出异常,而是返回null,它返回引用,可以放在赋值语句右边,赋值给目标类型的变量,在使用时,要判断返回引用类型是否为空。
Myclass mc = new Myclass();
IIfc1 fc = mc as IIfc1; //as运算符的使用
if(fc!=null)
{
Console.WriteLine("That's right!");
}
- 实现多个接口:如果要实现多个接口,则在基类列表中依次列出,逗号隔开,在类中要实现所有接口的成员;如果有多个要实现的接口具有相同的成员,只需要实现一个成员就可以满足要求;实现多个接口的引用方式如同实现单一接口的引用一样,可以通过强制类型转换,也可以通过as运算符实现。
interface If1
{
void Print1(string s1);
}
interface If2
{
void Print2(string s2);
}
class Myclass1 : If1,If2
{
public void Print1(string s1)
{
Console.WriteLine("Print1:{0}",s1);
}
public void Print2(string s2)
{
Console.WriteLine("Print2:{0}",s2);
}
}
class Program
{
static void main()
{
Myclass1 mc1 = new Myclass1();
mc1.Print1("自动化1401班,加油!");
mc1.Print2("越努力,越幸运!");
Console.WriteLine("。。。。。。。。。。。。。。。。。。。。。。。");
If1 fc1 = mc1 as If1;
If2 fc2 = mc1 as If2;
if((fc1!=null)&&(fc2!=null))
{
fc1.Print1("加油,2019!");
fc2.Print2("奋斗!2019!");
}
}
}
执行结果:
- 在派生成员中实现接口:此时,就是在基类中实现接口的方法,在派生类中实现接口,示例:
interface Ifc
{
string Print1();
}
class Myclass2 //在基类中实现接口的方法
{
public string name;
public string Print1()
{
return name;
}
}
class Myderived : Myclass2,Ifc
{ }
class Program
{
static void main()
{
Myderived myc = new Myderived();
myc.name = "加油啊,每一个追梦人!";
Console.WriteLine(myc.Print1());
}
}
执行结果:
- 显示接口成员实现:所谓的显示接口成员实现,只不过在类中声明接口成员时,要使用接口名点成员名的方式,为了突出该成员来自于哪个接口,此时接口成员的实现已经不属于类级别的实现,需要强制类型转换。在多个接口成员实现中运用更好,下面是单一接口的显示接口成员实现。
interface Ifc3
{
void GetName();
void GetAge();
}
class Mybaseclass:Ifc3
{
public string name;
public int age;
void Ifc3.GetName() //没有修饰符
{
Console.WriteLine("你的名字:{0}",name);
}
void Ifc3.GetAge()
{
Console.WriteLine("你的年龄:{0}",age);
}
}
class Program
{
static void Main()
{
Mybaseclass mybcl = new Mybaseclass();
mybcl.name = " Janms";
mybcl.age = 25;
Ifc3 ifc3 = (Ifc3)mybcl;
ifc3.GetName();
ifc3.GetAge();
}
}
执行结果:
- 接口作为一种引用类型,当然也可以继承,一个接口可以继承多个接口,在基接口列表中以逗号隔开,最终的接口会包含它声明的所有接口和所有基接口的成员,当然在类中要实现所有接口成员;不同的类也可以实现同一个接口,实现的过程是独立的。
interface Ifc3
{
void GetName();
void GetAge();
}
interface Ifc
{
string Print1();
}
interface Ifc5 :Ifc3,Ifc //接口继承
{ }
class Myclass: Ifc5
{
... //实现接口的所有成员,移植上面的示例代码即可
}
class Myclass1: Ifc5不同的类实现同一接口
{
... //实现接口的所有成员,赋予不同的功能即可
}