【一文了解】C#基础-接口
目录
1. 定义
2. 接口的特点与规则
3. 接口的实现
3.1单接口实现
3.2多接口实现
4. 接口的作用和用途
1)扩展行为
2)规范行为
3)降低耦合
5. 接口与继承的比较
1)继承
2)接口
6. 接口与抽象类的比较
1)IComparable(比较器,常用)
2)IComparer(比较器)
3)IEnumerable(枚举器,常用)
4)IEnumerator(枚举器)
本篇文章来分享一下C#的接口。从接口的定义、特点与规则、接口的实现、接口与继承的比较、接口与抽象类的比较等来详细学习接口。
1. 定义
在C#中,接口(interface)是用来定义类或结构(struct)所实现的一组公共行为的抽象。接口本质上定义了行为规范,但不实现行为。接口中的所有成员都是抽象的,它们只声明不实现,所有成员默认是public,不能有字段,也不能有实现代码。接口名建议用”I”开头,其后单词首字母大写 ,如IFlyable,IDriveable
public interface IFlyable
{void Fly();//接口中的方法默认是抽象的
}
简而言之,接口是规范,定义一组对外的行为规范,要求它的实现类必须实现接口的所有成员。其中实现接口的方法不能加override。
2. 接口的特点与规则
1)接口中不能包含字段:接口只能包含方法、属性、索引器和事件,不能包含任何字段。
2)所有成员默认是public:接口中的方法、属性、事件等成员默认是public,不能显式指定访问修饰符。接口的成员不能有访问修饰符,也不能使用abstract关键字。
public interface IDriveable
{void Drive();//无需使用abstract,默认即为抽象方法
}
3)接口中只能定义抽象成员:接口的所有成员默认都是抽象的,因此不需要再使用abstract关键字显式声明。
4)接口不能实例化:接口无法直接创建实例,必须通过实现接口的类或结构来创建对象。如,接口 iObj=new 实现类();
3. 接口的实现
3.1单接口实现
实现接口时,类必须实现接口中的所有成员,否则该类会被标记为抽象类。
public class Car : IDriveable
{public void Drive(){Console.WriteLine("Driving...");}
}
3.2多接口实现
C#允许类实现多个接口,接口之间的多继承是允许的。实现类必须实现接口中的所有成员。包括隐式实现与显式实现。
1)隐式实现:最常见的实现方式,直接实现接口中的成员,默认是public。
2)显式实现:通过接口名称显式实现接口成员,且这些成员在实现类中是private的,只有通过接口类型的引用才能调用。
//隐式实现
public class Car : IDriveable, IFlyable
{public void Drive() => Console.WriteLine("Driving...");public void Fly() => Console.WriteLine("Flying...");
}
//显式实现
public class Car : IDriveable, IFlyable
{void IDriveable.Drive() => Console.WriteLine("Driving...");void IFlyable.Fly() => Console.WriteLine("Flying...");
}
=>被称为表达式主体运算符,是一种简洁的语法,用于将方法、属性、索引器等成员的实现压缩为单行代码,适用于那些仅包含单一表达式的成员。
4. 接口的作用和用途
1)扩展行为
接口允许你在不改变已有类的情况下,扩展类的功能。例如,假设有一个Car类,它没有飞行功能,但我们可以通过实现IFlyable接口,给Car类增加飞行的功能,而不必直接修改原类。
2)规范行为
接口允许我们定义一组行为的规范,使得不同类在行为上保持一致。例如,不同种类的交通工具(汽车、飞机、船只等)都可以实现IDriveable接口,这样我们可以用统一的方式对不同的交通工具进行操作。
3)降低耦合
接口允许代码与实现细节解耦,增强代码的可扩展性和可维护性。使用接口可以降低类与类之间的直接依赖,便于未来的扩展和修改。
5. 接口与继承的比较
1)继承
①类继承只能支持单一继承。一个类只能继承自一个父类。
②类继承是继承父类的具体实现,并可能重写某些方法。
//父类(基类)
public class Animal
{public string Name { get; set; }//父类方法public void Eat(){Console.WriteLine($"{Name} is eating.");}//虚方法,允许子类重写public virtual void Speak(){Console.WriteLine($"{Name} makes a sound.");}
}//子类(派生类)
public class Dog : Animal
{public string Breed { get; set; }//重写父类方法public override void Speak(){Console.WriteLine($"{Name} barks.");}
}public class Program
{public static void Main(){Dog dog = new Dog { Name = "Buddy", Breed = "Golden Retriever" };dog.Eat();//继承自父类的方法,输出:Buddy is eating.dog.Speak();//重写后的方法,输出:Buddy is eating.}
}
2)接口
①接口支持多继承,一个类可以实现多个接口。
②接口只定义行为规范,不关心实现细节,避免了类之间紧耦合。
public interface IAnimal
{void Eat();void Sleep();
}
public interface ISwimmable
{void Swim();
}//类实现多个接口
public class Duck : IAnimal, ISwimmable
{public void Eat(){Console.WriteLine("Duck is eating.");}public void Sleep(){Console.WriteLine("Duck is sleeping.");}public void Swim(){Console.WriteLine("Duck is swimming.");}
}public class Program
{public static void Main(){Duck duck = new Duck();duck.Eat();//实现自 IAnimal 接口,输出:Duck is eating.duck.Sleep();//实现自 IAnimal 接口,输出:Duck is sleeping.duck.Swim();//实现自 ISwimmable 接口,输出:Duck is swimming.}
}
| 特性 | 继承(Class) | 接口(Interface) |
|---|---|---|
| 继承结构 | 单继承:一个类只能继承自一个父类 | 支持多继承:一个类可以实现多个接口 |
| 实现细节 | 继承父类的实现,子类可以重写父类的方法 | 只定义行为规范,不关心实现细节 |
| 使用场景 | 用于描述类之间的“是一个”关系(例如:狗是动物) | 用于定义不同类可以共享的行为(例如:可游泳的动物) |
| 访问修饰符 | 可以使用访问修饰符(public, private等) | 所有成员默认是公共的(public) |
| 构造函数 | 可以有构造函数 | 接口不能有构造函数 |
总结:
类与类:只能单继承。
类与接口:可以多实现(一个类可以实现多个接口)。
接口与接口:可以多继承(一个接口可以继承多个接口)。
6. 接口与抽象类的比较
1)接口:当需要定义一个行为的规范,并允许多个类实现该行为时,使用接口。例如,IDriveable接口可以被多个类(如Car、Truck)实现。
//定义接口 IDriveable
public interface IDriveable
{void Drive(); // 接口方法,只定义行为的规范,不提供实现
}//类 Car 实现 IDriveable 接口
public class Car : IDriveable
{public void Drive(){Console.WriteLine("The car is driving.");}
}//类 Truck 实现 IDriveable 接口
public class Truck : IDriveable
{public void Drive(){Console.WriteLine("The truck is driving.");}
}public class Program
{public static void Main(){IDriveable car = new Car();car.Drive();//调用 Car 类中的 Drive 方法,输出:The car is driving.IDriveable truck = new Truck();truck.Drive();//调用 Truck 类中的 Drive 方法,输出:The truck is driving.}
}
2)抽象类:当希望定义一些通用的行为,并允许一些方法在子类中被重写时使用抽象类。例如,Animal类可以是抽象类,包含一些通用的行为(如Eat方法),同时定义一些抽象方法(如MakeSound方法)。
//定义抽象类 Animal
public abstract class Animal
{//已实现的通用方法public void Eat(){Console.WriteLine("The animal is eating.");}//抽象方法,要求子类实现public abstract void MakeSound();
}//类 Dog 继承 Animal,并实现 MakeSound 方法
public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Dog Wangwang.");}
}//类 Cat 继承 Animal,并实现 MakeSound 方法
public class Cat : Animal
{public override void MakeSound(){Console.WriteLine("Cat MiaoMiao.");}
}public class Program
{public static void Main(){Animal dog = new Dog();dog.Eat();//调用父类 Animal 中的 Eat 方法,输出:The animal is eating.dog.MakeSound();//调用子类 Dog 中的 MakeSound 方法,输出:Dog Wangwang.Animal cat = new Cat();cat.Eat();//调用父类 Animal 中的 Eat 方法,输出:The animal is eating.cat.MakeSound();//调用子类 Cat 中的 MakeSound 方法,输出:Cat MiaoMiao.}
}
| 特性 | 接口(Interface) | 抽象类(Abstract Class) |
|---|---|---|
| 成员实现 | 不能包含实现,所有成员默认为抽象的 | 可以包含实现和抽象方法 |
| 字段 | 不能包含字段 | 可以包含字段 |
| 多继承支持 | 一个类可以实现多个接口 | 不支持多继承,一个类只能继承一个抽象类 |
| 方法实现 | 接口的方法只能声明,不能提供实现 | 抽象类可以有部分实现,也可以有抽象方法 |
| 构造函数 | 接口不能有构造函数 | 抽象类可以有构造函数 |
| 访问修饰符 | 接口成员默认是 public,不能使用其他访问修饰符 | 抽象类可以定义不同的访问修饰符 |
| 使用场景 | 用于定义一组行为规范,多个类可以实现这些行为 | 用于定义类的通用行为,允许部分实现并强制子类实现抽象方法 |
简而言之,接口更多用于行为的抽象,而抽象类则更多用于功能的抽象和实现。想要更详细了解继承和抽象类的有关知识,可以参考【超详细】C#基础-面向对象三大特性:封装、继承
7. 接口在C#中的应用
C#中有很多常用的接口,帮助我们统一不同类的行为。以下是一些常见的接口:
1)IComparable(比较器,常用)
类内继承,通过实现CompareTo方法来自定义对象的比较规则,用于比较对象的大小。
2)IComparer(比较器)
比较器继承,通过实现Compare方法,自定义两个对象的比较规则,常用于排序比较。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace InterfacePro
{//调用端class Program{static void Main(string[] args){Student zs = new Student{Id = 1001,Age = 19,Weight = 140};Student ls = new Student{Id = 1002,Age = 18,Weight = 160};//写法1:自定义对象的比较int a = zs.Age.CompareTo(ls.Age);//写法2:一般做法,自定义的类只选择一个属性去比较,实现比较接口IComparableint b = zs.CompareTo(ls);//写法3:基于写法2,如果还要比较其他属性,因为要遵守开闭原则,此时要实现另一个比较器WeightCompare weightCom = new WeightCompare();int c = weightCom.Compare(zs,ls);}}//定义端 复用class Student:IComparable{public int Id { get; set; }public int Age { get; set; }public int Weight { get; set; }public int CompareTo(object obj){return this.Id.CompareTo((obj as Student).Id);}}class WeightCompare : IComparer{public int Compare(object x, object y){return (x as Student).Weight.CompareTo((y as Student).Weight) ;}}
}
3)IEnumerable(枚举器,常用)
通过实现GetEnumerator方法返回一个迭代器IEnumerator,使类型支持简单迭代(foreach)。
4)IEnumerator(枚举器)
本质是一组yield return的语句,通过MoveNext进行逐段访问,自己可以控制迭代的节奏。
public class MyCollection : IEnumerable
{private int[] items = { 1, 2, 3 };public IEnumerator GetEnumerator(){foreach (var item in items){yield return item;}}
}
好了,本次的分享到这里就结束啦,希望对你有所帮助~
相关文章:
【一文了解】C#基础-接口
目录 1. 定义 2. 接口的特点与规则 3. 接口的实现 3.1单接口实现 3.2多接口实现 4. 接口的作用和用途 1)扩展行为 2)规范行为 3)降低耦合 5. 接口与继承的比较 1)继承 2)接口 6. 接口与抽象类的比较 1)IComparable(比较器,常用) 2)IComparer(比较器)…...
活着就好20241210
亲爱的朋友们,大家早上好!🌞 今天是10号,星期二,2024年12月的第十天,同时也是第50周的开始,农历甲辰[龙]年十一月初六日。在这晨光熹微的美好时刻,愿那温暖而明媚的阳光轻轻拂过你的…...
多表设计 - 一对一多对多
一.一对一关系概述: 例如:一位用户只能有一张身份证,一张身份证也只能对应一位用户 如果用户基本信息查询频率比用户身份信息查询频率高,为了提高效率,可拆分为两张表: 此时如何体现一对一的关系呢…...
实现 DataGridView 下拉列表功能(C# WinForms)
本文介绍如何在 WinForms 中使用 DataGridViewComboBoxColumn 实现下拉列表功能,并通过事件响应来处理用户的选择。以下是实现步骤和示例代码。 1. 效果展示 该程序的主要功能是展示如何在 DataGridView 中插入下拉列表,并在选择某一项时触发事件。 2.…...
使用Java创建RabbitMQ消息生产者的详细指南
目录 在现代分布式系统中,消息队列是实现异步通信的重要工具。RabbitMQ作为一种流行的开源消息代理,支持多种消息协议,广泛应用于微服务架构和事件驱动的应用程序中。本文将深入探讨如何使用Java创建RabbitMQ的消息生产者,发送消息…...
【LC】160. 相交链表
题目描述: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意&…...
Spark架构及运行流程
Spark架构图 Driver: 解析用户的应用程序代码,转化为作业(job)。创建SparkContext上下文对象,其负责与资源管理器(ClusterManager)通信,进行资源的申请、任务的分配和监控等。跟踪Executor的执行情况。可通过UI界面查询运行情况。…...
Linux安装Python2.7.5(centos自带同款)
卸载已安装的python,防止版本兼容问题 rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps 删除残余文件 whereis python |xargs rm -frv 安装前提是已安装gcc和g gcc --version g --version 下载安装python2.7.5 https://www.python.org/downloads/release/pyt…...
上传ssh公钥到目标服务器
创建密钥 ssh-keygen -t rsa -b 4096 -C "xxxx.xx"上传 sudo ssh-copy-id -i /Users/xx/.ssh/id_rsa.pub root127.0.0.1...
【LLMs】用LM Studio本地部署离线大语言模型
文章目录 一、下载LM Studio二、下载大语言模型1. 查看模型介绍2. 点击模型文件进行下载2.1 完整下载2.2 部分下载 三、加载模型1. 打开LM Studio图形化界面,点击**My Models**2. 然后,点击“...”,选择“change”,选择刚下载好的…...
SpringBoot下类加入容器的几种方式
SpringBoot下类加入容器的几种方式 在 Spring Boot 中,类加入容器的方式不仅多样,而且每种方式都有其特定的使用场景。以下是几种常见的将类加入 Spring 容器的方法及其适用场景: 1. 使用 Component 及其派生注解 使用场景:当开…...
【Mysql】忘记Root密码后如何不影响数据进行重置密码
方法一:通用方法--启动时跳过权限表 1> 停止数据库 以管理员方式打开cmd!! C:\Users\Administrator>net stop mysql MySQL 服务正在停止.. MySQL 服务已成功停止。 2> 启动时跳过权限表 mysqld --console --skip-grant-tables -…...
宝塔内设置redis后,项目以及RedisDesktopManager客户端连接不上!
项目展现问题: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to xxx.宝塔外链.ip.xxxx:6379 redis客户端连接失败: 1、宝塔中确认redis端口已放行 2、修改redis的配置 bind&#x…...
一文了解模式识别顶会ICPR 2024的研究热点与最新趋势
简介 对模式识别研究领域前沿方向的跟踪是提高科研能力和制定科研战略的关键。本文通过图文并茂的方式介绍了ICPR 2024的研究热点与最新趋势,帮助读者了解和跟踪模式识别的前沿研究方向。本推文的作者是黄星宇,审校为邱雪和许东舟。 一、会议介绍 ICPR…...
【深度学习】深刻理解BERT
BERT(Bidirectional Encoder Representations from Transformers)是由Google于2018年提出的一种预训练的语言表示模型,它基于Transformer架构并能够处理自然语言处理(NLP)中的多种任务。BERT的核心创新是其使用了双向编…...
一种基于通义千问prompt辅助+Qwen2.5-coder-32b+Bolt.new+v0+Cursor的无代码对话网站构建方法
前言 今年似乎大模型之间的“内卷”已经有些偃旗息鼓了,各大技术公司逐渐从单纯追求模型参数量的竞赛中抽身,转向更加注重模型的实际应用效果与效率,开始内卷起了LLM“载具” 不知道这个词是不是我第一个发明的哈,总之我更喜欢…...
Java版-图论-最小生成树-Kruskal算法
实现描述 为了造出一棵最小生成树,我们从最小边权的边开始,按边权从小到大依次加入,如果某次加边产生了环,就扔掉这条边,直到加入了 n-1 条边,即形成了一棵树。 实现代码 首选我们对所有的边,…...
计算机网络知识总结
1.网络协议是什么? 在计算机网络要做到有条不紊地交换数据,就必须遵守一些约定好的规则,比如交换数据地格式,是否需要发送一个应答信息。这些规则被称为网络协议。 分层结构 应用层:为计算机用户提供服务表示层&…...
普通算法——欧拉筛
欧拉筛 思路: 对欧拉筛的实现,主要是依靠一个数组模拟的栈来实现,核心思路为用栈储存已经发现的素数 在之后的遍历中,即可以素数数组中的数为因数来筛出此素数的倍数 遍历是以当前的 i i i 值为基数,来乘当前素数数…...
【知识科普】DNS(域名解析服务)深入解读
文章目录 概述一、基本概念二、域名解析的原理三、域名解析的类型四、域名解析的常见问题及解决方法五、域名解析的重要性 部署一、准备环境二、安装DNS软件三、配置DNS服务器四、测试DNS解析五、维护和管理DNS服务器 配置文件一、BIND DNS服务器配置文件格式二、Windows系统DN…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
