C#入门(7):接口详细介绍与代码演示

在C#中,接口是一种定义行为的契约。接口可以定义方法、属性、索引器和事件的签名,但它们都没有实现(即,接口包含的都是抽象成员)。任何实现了特定接口的类都需要提供接口定义的所有成员的具体实现。

C#接口的一些主要特点

以下是C#接口的一些主要特点:

  1. 抽象成员:接口的所有成员都是抽象的,它们没有具体的实现。这意味着接口只定义了成员的签名,而不定义其行为。

  2. 多接口实现:一个类可以实现多个接口。这意味着你可以使用接口来定义可以由多个类共享的行为。

  3. 隐式和显式实现:一个类可以选择显式地实现接口的成员。这意味着这些成员只有当它们被视为接口类型时才可见。

  4. 无法实例化:接口不能被实例化。这意味着你不能创建一个接口的实例,但你可以创建一个实现了接口的类的实例。

下面是一个接口的示例:

public interface IFlyable
{void Fly();
}public class Bird : IFlyable
{public void Fly(){Console.WriteLine("The bird is flying");}
}public class Plane : IFlyable
{public void Fly(){Console.WriteLine("The plane is flying");}
}// 在其他地方使用
IFlyable flyableObject = new Bird();
flyableObject.Fly(); // 输出 "The bird is flying"flyableObject = new Plane();
flyableObject.Fly(); // 输出 "The plane is flying"

在这个例子中,IFlyable接口定义了一个Fly方法,Bird类和Plane类都实现了这个接口,并提供了Fly方法的实现。然后,我们可以创建一个IFlyable引用,并让它引用一个Bird对象或一个Plane对象。当我们通过这个引用调用Fly方法时,CLR会根据实际的对象类型来调用正确的方法实现。这就是接口和多态的一种应用,使得我们可以写出更通用的代码,而不需要知道或检查对象的具体类型。

接口在C#中的使用相当广泛,除了上述基本特性外,接口还有以下几个重要的特性和使用场景:

  1. 接口继承:接口可以继承其他接口,这意味着一个接口可以通过继承来增加更多的成员。继承的接口必须提供基接口所有成员的实现。

    public interface IDrawable
    {void Draw();
    }public interface IMovable : IDrawable
    {void Move();
    }public class Shape : IMovable
    {public void Draw(){Console.WriteLine("Drawing shape");}public void Move(){Console.WriteLine("Moving shape");}
    }
    ```在这个例子中,`IMovable`接口继承了`IDrawable`接口,所以`IMovable`接口包含了`Draw()`和`Move()`两个方法。`Shape`类实现了`IMovable`接口,因此需要提供`Draw()`和`Move()`两个方法的实现。
  2. 接口和抽象类的区别:虽然接口和抽象类都可以定义抽象成员,但它们之间有一些关键的区别。接口只能定义抽象成员,而抽象类既可以定义抽象成员也可以定义具体成员。接口不能有字段和构造函数,而抽象类可以。一个类可以实现多个接口,但只能继承一个抽象类。

  3. 接口的用途:接口常常被用于定义可以由多个类共享的行为。因为一个类可以实现多个接口,所以接口是实现多重继承的一种方式。接口也常用于定义插件或组件的API,或者定义用于测试的存根(stub)和模拟(mock)对象。

  4. 接口和装箱/拆箱:如果一个值类型(如结构体)实现了一个接口,那么将该值类型的值转换为接口类型会造成装箱操作,这可能会影响性能。所以,在性能敏感的代码中,我们要尽量避免这种装箱操作。

总的来说,接口是一种强大的工具,它允许我们定义可由多个类共享的行为,并支持在不知道或不检查对象的具体类型的情况下编写通用的代码。我们应该充分利用接口来提高代码的可复用性和可维护性。

接口和装箱/拆箱

在C#中,装箱和拆箱是值类型(例如整数、布尔值和结构)和引用类型(例如类和接口)之间转换的过程。

**装箱(Boxing)**是将值类型转换为引用类型的过程。具体来说,装箱操作创建了值类型的一个副本,并将其存储在堆上,然后返回一个指向这个副本的引用。

**拆箱(Unboxing)**是将引用类型转换回值类型的过程。具体来说,拆箱操作将堆上的值复制到栈上。

装箱和拆箱操作可能会影响性能,特别是在大量的装箱和拆箱操作中,因为这涉及到堆分配和垃圾回收。

当一个值类型实现了一个接口,将该值类型的值赋给一个接口类型的变量时,会发生装箱操作。以下是一个示例:

public interface IExample
{void DoSomething();
}public struct Value : IExample
{public void DoSomething(){Console.WriteLine("Doing something...");}
}// 在其他地方使用
IExample example = new Value(); // 这里发生了装箱操作
example.DoSomething();

在上述示例中,Value是一个结构体,实现了IExample接口。当我们创建一个Value的实例并赋值给一个IExample类型的变量时,会发生装箱操作。

反过来,如果我们有一个装箱的值类型,我们可以通过拆箱操作将其转换回原来的值类型:

IExample example = new Value(); // 这里发生了装箱操作
Value value = (Value)example; // 这里发生了拆箱操作
value.DoSomething();

在这个例子中,我们首先创建了一个Value的实例并赋值给一个IExample类型的变量,这是一个装箱操作。然后,我们将IExample类型的变量转换回Value类型,这是一个拆箱操作。

总的来说,我们应该尽量避免不必要的装箱和拆箱操作,特别是在性能敏感的代码中,因为装箱和拆箱都涉及到堆分配和可能的垃圾回收。

在性能敏感的环境中,理解和避免不必要的装箱和拆箱操作是非常重要的。以下是一些额外的信息和技巧:

  1. 避免将值类型转换为接口:如前面所提,一个值类型实现一个接口并赋值给接口类型会导致装箱。如果你有一个值类型,并且你需要频繁地将它转换为接口类型,那么你可能需要考虑将这个值类型改为引用类型,以避免装箱。

  2. 使用泛型以避免装箱:在.NET 2.0中,引入了泛型,这是一种允许你编写可以处理任意类型而不需要转换为object或接口的代码的方式。泛型可以避免许多不必要的装箱操作。例如,List就是一个泛型类型,你可以使用List来存储整数,而不需要将它们装箱为object或接口。

  3. 避免在值类型上调用ToString或其他虚拟方法:值类型可以覆写object类的虚拟方法,例如ToStringGetHashCodeEquals。然而,如果你有一个值类型的变量,并且你在这个变量上调用一个虚拟方法,那么这会导致装箱。为了避免这种装箱,你可以在值类型上直接调用这些方法。例如,int类型有一个ToString方法,你可以直接在int变量上调用这个方法,而不需要将int变量转换为object

  4. 理解装箱和拆箱的性能影响:虽然装箱和拆箱操作可能会影响性能,但在许多情况下,这种影响是可以接受的。装箱和拆箱涉及的是堆分配和垃圾回收,这在现代计算机上通常是非常快的。除非你的代码在一个性能敏感的环境中执行,或者你的代码进行了大量的装箱和拆箱操作,否则你可能不需要过于担心这个问题。

总的来说,理解装箱和拆箱以及它们对性能的影响可以帮助你编写更有效的代码。然而,你应该避免过早优化,除非你发现装箱和拆箱操作真的对你的应用程序的性能产生了重大影响。在大多数情况下,代码的可读性、可维护性和正确性比微小的性能优化更重要。

在同一个类中如何实现多个具有相同方法名的接口

在C#中,如果一个类要实现多个具有相同方法名的接口,可以通过显式接口实现来解决命名冲突。下面是一个简单的示例,演示了如何在同一个类中实现两个具有相同方法名的接口:

using System;// 定义两个接口,它们都有一个相同的方法名
interface IInterface1
{void CommonMethod();
}interface IInterface2
{void CommonMethod();
}// 实现类,通过显式接口实现解决命名冲突
class MyClass : IInterface1, IInterface2
{// IInterface1 接口的显式实现void IInterface1.CommonMethod(){Console.WriteLine("Implementation of CommonMethod from IInterface1");}// IInterface2 接口的显式实现void IInterface2.CommonMethod(){Console.WriteLine("Implementation of CommonMethod from IInterface2");}
}class Program
{static void Main(){// 创建 MyClass 实例MyClass myClass = new MyClass();// 通过 IInterface1 调用 CommonMethod((IInterface1)myClass).CommonMethod();// 通过 IInterface2 调用 CommonMethod((IInterface2)myClass).CommonMethod();Console.ReadLine();}
}

在这个例子中,MyClass 类同时实现了 IInterface1IInterface2 接口,这两个接口都有一个名为 CommonMethod 的方法。为了解决命名冲突,我们在实现类中使用了显式接口实现。在 MyClass 中,我们分别实现了 IInterface1IInterface2 接口的 CommonMethod 方法。在使用这些方法时,我们需要通过接口类型来调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/151842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode运行dlv报错超时

描述 点击F5运行dlv调试go代码时报错:couldnt start dlv dap: connection timeout 解决方式 在网上搜索这个报错,据说是dlv的配置问题,修改配置后还是不行。有人说是dlv和go的版本不匹配,就朝这个方向试试 go版本改为1.19之后…

网上被吹爆的Spring Event事件订阅有缺陷,不要用

Spring Event事件订阅框架,被网上一些人快吹上天了,然而我们在新项目中引入后发现,这个框架缺陷很多,玩玩可以,千万不要再公司项目中使用。还不如自己手写一个监听者设计模式,那样更稳定、可靠。 之前我已…

C# params关键字

在C#中,params关键字用于指定一个方法参数,它可以接受任意数量的参数,或者说是一个参数数组。当使用params关键字时,你可以向方法传递逗号分隔的参数列表,或者是一个数组。在方法内部,这些参数被处理为一个…

ARM CoreLink CCN 互连总线介绍

NIC NOC CCI CMN CNN NI cmn-700 nic-700 ni-700 MLGB这都是啥玩意? 后期博文或视频将会更新这一系列。今天先温习一下CNN的概念,这是来自2014年的文章,然后稍微整理总结一番。 以下是正文… 现代主流和优质 ARM 片上系统 (SoC) 产品使用 CoreLink 缓存一致性网络 (CCN) 504…

SpringBoot-过滤器Filter+JWT令牌实现登录验证

登录校验-Filter 分析 过滤器Filter的快速入门以及使用细节我们已经介绍完了,接下来最后一步,我们需要使用过滤器Filter来完成案例当中的登录校验功能。 我们先来回顾下前面分析过的登录校验的基本流程: 要进入到后台管理系统,我…

java 位运算 表示状态小记

单一状态码var i2 1 << 2; //4 左移var i3 1 << 3; //8 左移var i4 1 << 4; //16 左移var i5 1 << 5; //32 左移数据状态值var huo i3 | i4 | i2; //28 或//判断状态System.out.println("yu1" (huo & i2)); // 4 & 与System.o…

CentOS 安装etcd集群 —— 筑梦之路

环境说明 192.168.1.11 192.168.1.12 192.168.1.13 yum在线安装 yum install etcd -y #etcd01 cat > /etc/etcd/etcd.conf <<EOF ETCD_NAMEetcd01 ETCD_LISTEN_PEER_URLS"http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS"http://0.0.0.0:2379&quo…

IDEA运行thymeleaf的html文件打开端口为63342且连不上数据库

这边贴apple.html代码 <!DOCTYPE html> <html xmlns:th"http://www.thymeleaf.org"> <head><meta charset"UTF-8"><title>User List</title> </head> <body> <h1>User List</h1> <table&…

elementui表格自定义指令控制显示哪些列可以拖动

Vue.directive(tableBorder, function (el, {value}) {// value允许传字符串数字和数组el.classList.add(z_table_hasBorder)let hasStyle el.querySelector(style)if(hasStyle){hasStyle.remove()}let style document.createElement(style)let str .z_table_hasBorder .el…

线上AB实验的日志分析

1&#xff0c;如果策略只影响部分商家/商品&#xff0c;则统计分析出受影响这部分的效果指标。 具体操作&#xff1a;在实验组圈选出 受策略影响的商家/商品&#xff0c;对这部分商家/商品&#xff0c;统计实验组VS对照组的效果指标。 分析出了 受影响这部分商家/商品的正向或…

【数据结构与算法】Kadane‘s算法(动态规划、最大子数组和)

文章目录 一、算法原理二、例题2.1 最大子数组和2.2 环形子数组的最大和 一、算法原理 Kadanes算法是一种用于解决最大子数组和问题的动态规划算法。这类问题的目标是在给定整数数组中找到一个连续的子数组&#xff0c;使其元素之和最大&#xff08;数组含有负数&#xff09;。…

【Linux 内核分析课程作业 1】mmap 实现一个 key-valueMap

作业一 功能要求利用 mmap(虚拟内存映射文件) 机制实现一个带持久化能力的 key-valueMap 系统&#xff0c;至少支持单机单进程访问。(可能用到的 linux API: mmap、msync、mremap、munmap、ftruncate、fallocate 等) 电子版提交方式&#xff1a; 2023 年 11 月 20 日 18:00 前通…

IObit Unlocker丨解除占用程序软件

更多内容请收藏&#xff1a;https://rwx.tza-3.xyz 官网&#xff1a;IObit Unlocker “永远不用担心电脑上无法删除的文件。” 界面简单&#xff0c;支持简体中文&#xff0c;一看就会&#xff0c;只需要把无法删除/移动的文件或整个U盘拖到框里就行。 解锁率很高&#xff0c;…

Unity热更新资源和代码-(学前必读)

系列文章目录 在学习完整的热更新流程之前&#xff0c;需要对lua、xlua、AssetBundle有一定的了解&#xff0c;没有基础的同学&#xff0c;可以看之前的博客&#xff0c;有一定的了解后再学习就会事半功倍了 Lua入门课程 AssetBundle入门 xLua入门 前言 在对热更新有初步了解…

Java爬虫的使用案例及简单总结

通过三个简单的案例,来实现的,都是不加验证的情况下. 如果有拼图验证网上也有对应的实现方法自行查找即可. 这里仅仅是一个简单的Demo, 练习使用 0. 爬取网站的配置: article:config:#中央新闻网-三农头条数据部分ntvUrl: https://www.ntv.cn/# 全国农技推广网- 农技动态部分n…

elasticsearch 概述

初识elasticsearch 了解ES elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在GitHub搜索代码 在电商网站搜索商品 ELK技术栈 elasticsearc…

简述如何使用Androidstudio对文件进行保存和获取文件中的数据

在 Android Studio 中&#xff0c;可以使用以下方法对文件进行保存和获取文件中的数据&#xff1a; 保存文件&#xff1a; 创建一个 File 对象&#xff0c;指定要保存的文件路径和文件名。使用 FileOutputStream 类创建一个文件输出流对象。将需要保存的数据写入文件输出流中…

Vue3的异步组件使用

通过defineAsyncComponent引入组件&#xff0c;使用Suspense渲染 Suspense有两个插槽&#xff0c;一个default一个fallback <template><Suspense><template #default><userCard></userCard></template><template #fallback>加载中…

我叫:插入排序【JAVA】

1.自我介绍 插入式排序属于内部排序法,是对于欲排序的元素以插入的方式找寻该元素的适当位置&#xff0c;以达到排序的目的。 2.继承我的思想 插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包…

WPF ObservableCollection 和 BindingList 有什么区别

ObservableCollection<T>和BindingList<T>都是.NET Framework中的泛型集合类型&#xff0c;它们都支持数据绑定和元素的增加、删除、修改等操作。然而&#xff0c;它们之间存在一些关键的差异&#xff0c;使它们在不同的场景下更有用。 ObservableCollection: Ob…