一、什么是接口
接口是指定一组函数成员而不实现它们的引用类型。
实现接口: 只能由类和结构来实现接口。
二、声明接口
接口声明不能包含以下成员:
- 数据成员
- 静态成员
接口声明只能包含如下类型的非静态成员函数的声明:
- 方法
- 属性
- 事件
- 索引器
接口的访问性和接口成员的访问性之间的区别:
- 接口声明可以有任何的访问修饰符:public、protected、internal 或 private。
- 接口成员是隐式 public 的,不允许有任何访问修饰符,包括 public。
//正确,接口可以有访问修饰符
public interface IMyInterface2
{
//报错,接口成员不允许有访问修饰符
private int Method1(int nVar1, long lVar2);
}
三、接口是引用类型
我们可以通过把类对象引用强制转换为接口类型来获取指向接口的引用。
interface IIfc1
{
void PrintOut(string s);
}
class MyClass : IIfc1
{
public void PrintOut(string s)
{
Console.WriteLine($"Calling through:{ s }");
}
}
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
mc.PrintOut("object");//调用类对象的实现方法
IIfc1 ifc = (IIfc1)mc;//将类对象的引用转换为接口类型的引用
ifc.PrintOut("interface");//调用接口方法
Console.ReadKey();
}
}
四、接口和 as 运算符
当我们把类对象引用强制转换为接口类型时,如果类并没有实现接口的引用(比如类没有继承对应的接口,或者类没有完全实现继承接口里的方法),强制转换操作会抛出一个异常。
那么可以通过使用 as 运算符来避免这个问题:
- 如果类实现了接口,表达式返回指向接口的引用。
- 如果类没有实现接口,表达式返回 null 而不是抛出异常。
ILiveBirth b = a as ILiveBirth;
if(b != null)
Console.WriteLine($"Baby is called:{b.BabyCalled()}");
五、实现具有重复成员的接口
问题: 由于类可以实现任意数量的接口(继承多个接口),有可能两个或多个接口成员具有相同的签名和返回类型。
解决: 类可以实现单个成员来满足所有包含重复成员的接口。(在例子中,实现的单个成员都属于 IIfc1 和 IIfc2)
interface IIfc1
{
void PrintOut(string s);
}
interface IIfc2
{
void PrintOut(string s);
}
class MyClass : IIfc1, IIfc2
{
public void PrintOut(string s)
{
Console.WriteLine($"Calling through:{ s }");
}
}
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
mc.PrintOut("object");
Console.ReadKey();
}
}
输出结果:
Calling through:object
六、多个接口的引用
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
IIfc1 ifc1 = (IIfc1)mc;
IIfc2 ifc2 = (IIfc2)mc;
mc.PrintOut("object");
ifc1.PrintOut("interface 1");
ifc2.PrintOut("interface 2");
Console.ReadKey();
}
}
输出结果:
Calling through:object
Calling through:interface 1
Calling through:interface 2
七、显式接口成员实现
如果我们希望为每一个接口分离实现,我们可以创建显式接口成员实现。
显式接口成员实现有如下特性:
- 与所有接口实现相似,位于实现了接口的类或结构中。
- 它使用限定接口名称来声明,由接口名称和成员名称以及它们中间的点分离符号构造。
interface IIfc1{ void PrintOut(string s); }
interface IIfc2{ void PrintOut(string s); }
class MyClass : IIfc1, IIfc2
{
//不可用访问修饰符
void IIfc1.PrintOut(string s)
{
Console.WriteLine($"IIfc1:{ s }");
}
void IIfc2.PrintOut(string s)
{
Console.WriteLine($"IIfc2:{ s }");
}
//类内访问显式接口成员
public void Method()
{
//PrintOut("...");//编译错误
((IIfc1)this).PrintOut("interface 1");
}
}
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
//获取接口的引用
IIfc1 ifc1 = (IIfc1)mc;
IIfc2 ifc2 = (IIfc2)mc;
//mc.PrintOut("object");//错误
//显式实现
ifc1.PrintOut("interface 1");
ifc2.PrintOut("interface 2");
Console.ReadKey();
}
}
输出结果:
IIfc1:interface 1
IIfc2:interface 2
八、不同类实现一个接口的示例
interface ILiveBirth
{
string BabyCalled();
}
class Animal { }
class Cat:Animal, ILiveBirth
{
string ILiveBirth.BabyCalled()
{
return "kitten";
}
}
class Dog : Animal, ILiveBirth
{
string ILiveBirth.BabyCalled()
{
return "puppy";
}
}
class Bird : Animal
{
}
class Program
{
static void Main(string[] args)
{
Animal[] animalArray = new Animal[3];
animalArray[0] = new Cat();
animalArray[1] = new Bird();
animalArray[2] = new Dog();
foreach(Animal a in animalArray)
{
ILiveBirth b = a as ILiveBirth;
if (b != null)
Console.WriteLine($"Baby is called:{ b.BabyCalled() }");
}
Console.ReadKey();
}
}
输出结果:
Baby is called:kitten
Baby is called:puppy