C#学习笔记 -- 接口
1、什么是接口
-
接口指定一组函数成员, 而不实现他们的引用类型
-
只能类和结构来实现接口
例子
//声明实现接口的CA类 class CA : IInfo { public string Name; public int Age; //在类中实现接口的方法 public string GetAge() { return Age.ToString(); } public string GetName() { return Name; } }
class CB : IInfo { public string First; public string Last; public double PersonsAge; public string GetAge() { return PersonsAge.ToString(); } public string GetName() { return First + "·" + Last; } }
public interface IInfo { string GetName(); string GetAge(); }
public static class Printer { public static void PrintInfo(IInfo item) { Console.WriteLine($"名字: {item.GetName()}, 年龄: {item.GetAge()}"); } }
static void Main(string[] args) { CA a = new CA() { Name = "John Doe", Age = 35 }; CB b = new CB() { First = "James", Last = " Doe", PersonsAge = 33 }; PrintInfo(a); PrintInfo(b); }
(1)使用IComparable接口
-
Array.Sort()
依赖于IComparable
的接口public interface IComparable { int CompareTo(Object obj); } -
CompareTo()
方法返回值如下-
负数: 如果当前对象小于参数对象
-
正数: 如果当前对象大于参数对象
-
0: 两个对象相对
-
-
Sort()
使用的算法是依赖与使用对象的CompareTo()
来决定两个元素的次序,int
类型实现了IComparable
, 但是自定义类没有, 因此自定义类的数组无法使用Sort()
-
让类实现
IComparable
接口, 让Sort
方法可以用于自定义类型的对象
class MyClass : IComparable { public int TheValue; //实现接口方法 public int CompareTo(object obj) { MyClass mc = (MyClass)obj; return this.TheValue - mc.TheValue; } }
(2)实现一个接口, 类和接口必须要做的事情
-
在基类列表中列出接口名称
-
为接口的每个成员提供实现
2、声明接口
声明接口重要事项
-
接口可以使用任何访问修饰
public、protected、internal、private
-
接口成员是隐式
public
的, 不允许用任何访问修饰符, 包括public
-
接口声明不能包含以下成员
-
数据成员 (字段)
-
静态成员
-
-
接口声明只能包含如下类型的非静态成员函数的声明
-
方法
-
属性
-
事件
-
索引器
-
-
这些函数成员的声明不能包含任何实现代码, 必须使用分号代替每一个成员声明的主体
-
接口名称必须以大写的
I
开头 -
与类和结构一样, 接口声明也可以分割成分部接口声明
访问修饰符 interface IMyInterface1 { //不能有字段和静态成员 //成员不能用任何访问修饰符 Type DoStuff(Type nVar1, Type lVar2); }
3、实现接口
只有类和结构才能实现接口, 要实现接口, 必须有如下
-
在基类列表中包括接口名称
-
为每一个接口成员提供实现
注意
-
如果类实现了接口, 他必须实现接口所有成员
-
如果类派生自基类并实现了接口, 基类列表中的基类名称必须放在接口之前
class Derived : MyBaseClass, IIfc1, IIfc2 { //... }
4、接口是引用类型
-
不能直接通过类对象的成员访问接口
-
可以通过把类对象引用强制转换为接口类型来获取指向接口的引用
-
一旦有了接口的引用, 就可以使用
.
来调用接口的成员, 使用这个接口, 你不能调用不属于这个接口成员的类成员
class MyClass : IIfc1 { public void PrintOut(string s) { //... } }
interface IIfc1 { void PrintOut(string s); }
static void Main(string[] args) { MyClass mc = new MyClass(); //创建类对象 mc.PrintOut("object");//调用对象的实现方法 IIfc1 ifc = (IIfc1)mc;//转换为接口类型的引用 ifc.PrintOut("iterface");//调用接口方法 }
5、接口和as运算符
可以使用强制转换运算符来获取对象接口的引用, 另一个更好的方式是as运算符
如果将类对象引用强制转换为类未实现的接口的引用, 强制转换操作为抛出异常, 可以使用as运算符来避免这个问题
接口名称 接口引用 = 类对象引用 as 接口名称
-
如果类实现了接口, 表达式返回指向接口的引用
-
如果类没有实现接口, 表达式返回null而不是抛出异常
ILiveBirth b = a as ILiveBirth; if(b != null) { Console.WriteLine($"{b.BabyCalled()}"); }
6、实现多个接口
-
类或结构可以实现任意数量的接口
-
所有实现的接口必须列在基类列表中并以逗号分割(如果有基类名称, 则在其之后)
class MyData : IDataRetrieve, IDataStore { ... }
7、实现有重复成员的接口
由于类可以实现任意数量的接口, 有可能有两个或多个接口成员具有相同的签名和返回类型
interface IIfc1 { void PrintOut(string s); }
interface IIfc2 { void PrintOut(string s); }
-
如果一个类实现了多个接口, 并且其中一些接口成员具有相同的签名和返回类型
-
那么类可以实现单个成员来满足所有包含重复成员的接口
class MyClass : IIfc1, IIfc2 { public void PrintOut(string s) { Console.WriteLine($"PrintOut:{s}"); } }
static void Main(string[] args) { MyClass mc = new MyClass(); mc.Print("object"); }
8、多个接口的引用
-
可以通过对象强制转换为接口类型的引用, 来获取一个指向接口的引用
-
如果类实现了多个接口, 我们可以获取每个接口的独立引用
interface IIfc1 { void PrintOut(string s); }
interface IIfc2 { void PrintOut(string s); }
class MyClass : IIfc1, IIfc2 { public void PrintOut(string s) { Console.WriteLine($"s = {s}"); } }
static void Main(string[] args) { MyClass mc = new MyClass(); IIfc1 ifc1 = (IIfc1) mc; IIfc2 ifc2 = (IIfc2) mc; mc.PrintOut("object"); ifc1.PrintOut("Interface1"); ifc2.PrintOut("Interface2"); }
9、派生成员作为实现
实现接口的类可以从它的基类继承实现的代码
interface IIfc1 { void PrintOut(string s); }
class MyBaseClass { public void PrintOut(string s) { Console.WriteLine($"{s}"); } }
class Derived : MyBaseClass, IIfc1 { }
static void Main(string[] args) { Derived derived = new Derived(); derived.PrintOut("derived");//dervied }
-
父类实现了某个接口的方法
-
子类继承父类, 并且实现接口
-
子类中不实现接口方法, 就可以调用
10、显示接口成员实现
-
为每一个接口分离实现, 可以创建显示接口成员
-
与所有接口实现想死, 位于实现了接口的类或结构中
-
使用限定接口名称来声明, 由接口名称和成员名称以及他们中间的点来分隔符号构成
访问修饰符 返回类型 接口.方法(参数列表) { 实现 }
interface IIfc1 { void PrintOut(string t); }
interface IIfc2 { void PrintOut(string s); }
class MyClass1610 : IIfc1, IIfc2 { void IIfc1.PrintOut(string t) { Console.WriteLine($"IIfc1: {t}"); } void IIfc2.PrintOut(string s) { Console.WriteLine($"IIfc2: {s}"); } }
static void Main(string[] args) { MyClass1610 mc = new MyClass1610(); Interface1610.IIfc1 iifc1 = (Interface1610.IIfc1) mc; iifc1.PrintOut("iifc1"); Interface1610.IIfc2 iifc2 = (Interface1610.IIfc2) mc; iifc1.PrintOut("iifc2"); }
注意
-
在接口方法没有指向类级别实现, 而是包含了自己的代码
-
不能使用
MyClass1610
的对象来调用方法, 不存在类级别的Printout
方法
如果有显示接口成员实现, 类级别的实现是允许的, 担不是必须的, 显示实现满足了类火结构必须实现方法的需求, 因此, 可以有如下三种实现场景
-
类级别实现
-
显示接口成员实现
-
类级别和显示接口成员实现
访问接口成员实现
显示接口成员只能通过接口指向的引用来访问, 其他的类成员都不可用直接访问他们, 必须转换为接口引用
class MyClass1610 : IIfc1 { void IIfc1.PrintOut(string t) { Console.WriteLine($"IIfc1: {t}"); } public void Method1() { //编译错误 //PrintOut("x"); //this.PrintOut("x"); //转换为接口引用 ((IIfc1)this).PrintOut("xxx"); } }
这个限制对继承产生类重要的影响, 由于其他类成员不能直接访问显示接口成员实现, 派生类的成员也不能直接访问他们
11、接口可以继承接口
-
要指定某个接口继承其他接口, 形式如下
interface 派生接口 : 基接口1, 基接口2 { ... } -
类的基类只能有一个, 而接口可以有多个任意基接口
-
列表中的接口本身可以继承其他接口
-
结果接口包含它声明的所有成员和基接口的所有成员
-
interface IDataRetrieve { int GetData(); }
interface IDataStore { void SetData(int x); }
interface IData : IDataRetrieve, IDataStore { }
class MyData : IData { int nPrivateData; public int GetData() { return nPrivateData; } public void SetData(int x) { nPrivateData = x; } }
static void Main(string[] args) { MyData myData = new MyData(); myData.SetData(5); Console.WriteLine($"{myData.GetData()}"); }
12、不同类实现一个接口
interface ILiveBirth { string BabyCalled(); }
class Animal { }
class Dog : Animal, ILiveBirth { public string BabyCalled() { return "puppy"; } }
class Cat : Animal, ILiveBirth { public string BabyCalled() { return "pussy"; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了