Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C#接口新特性概览

C#接口新特性概览

作者头像
云峥百宝箱
发布于 2025-04-16 11:07:13
发布于 2025-04-16 11:07:13
4700
代码可运行
举报
运行总次数:0
代码可运行

接口新语法概览

csharp8.0
csharp8.0

在C#中,接口不再仅限于定义不带访问修饰符的方法签名。现在,接口可以包含:

  • 带默认实现的方法
  • 私有方法
  • 受保护方法
  • 静态方法
  • 抽象静态方法
  • 虚静态方法
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IOverall
{
    // 最普通的方法
    void Foo();

    // 属性
    string Name { get; set; }

    // 索引器
    int this[int index] { get; set; }

    // 事件
    event EventHandler OnNameChanged;

    // 带默认实现的方法
    void Bar() => Console.WriteLine("Bar");

    // 私有方法(需要带默认实现)
    private void NonPublicMethod1() 

    // 受保护方法(需要带默认实现)
    protected void NonPublicMethod2() 

    // 静态方法(需要带默认实现)
    static void StaticMethod() {
        Console.WriteLine("StaticMethod");
    }

    // 抽象静态方法
    static abstract void AbstractStaticMethod();

    // 虚静态方法(需要带默认实现)
    static virtual void VirtualStaticMethod() {
        Console.WriteLine("VirtualStaticMethod");
    }
}

属性和事件在接口中的本质是声明getter/setter以及事件的add/remove,而类中的属性和事件会后台生成对应的私有字段。索引器在接口中声明getter/setter,类中的索引器除非被标记为abstract,否则必须给出默认实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IPropertyAndEvent
{
    string Name { get; set; }

    string this[string key] { get; set; }

    event EventHandler? OnNameChanged;
}

public class ClassWithPropertyAndEvent : IPropertyAndEvent
{
    public string Name { get; set; } = "";

    public string this[string key] {
        get => "";
        set {}
    }

    public event EventHandler? OnNameChanged;
}

在C# 8.0中引入了接口中的默认实现,实现了接口的类可以对接口中的方法进行重写。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IFoo1
{
    void Foo() {
        Console.WriteLine($"这是接口{nameof(IFoo1)}中的一个包含默认实现的方法");
    }

    void Bar() {
        Console.WriteLine($"这是接口{nameof(IFoo1)}中的另一个包含默认实现的方法");
    }
}

public interface IFoo2
{
    void Foo() {
        Console.WriteLine($"这是接口{nameof(IFoo2)}中的一个包含默认实现的方法");
    }
}

public class DemoClass1 : IFoo1, IFoo2
{
    public void Bar() {
        Console.WriteLine($"这是{nameof(DemoClass1)}类对于接口中带有默认实现的方法的实现");
    }
}

使用默认方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var demo = new DemoClass1();

// 错误用法 - demo.Foo() 这样是无法调用Foo()的,因为DemoClass1中没有Foo方法的实现。
// 必须这样正确用法 - ((IFoo1)demo).Foo();

// demo.Bar() 结果为:这是DemoClass1类对于接口中带有默认实现的方法的实现
// ((IFoo1)demo).Bar() 结果为:这是DemoClass1类对于接口中带有默认实现的方法的实现

非公开方法一般有两个用途:不让类外面的代码使用,或者让类的公开方法来调用。在接口中使用非公开方法一般需要带有默认实现。

接口中的静态方法是属于接口的,而不是属于实现了该接口的某个类的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IStaticMethod
{
    static void StaticMethod() {
        Console.WriteLine("IStaticMethod.Foo");
    }
}

class DemoClass : IStaticMethod 

这样使用是错误的 DemoClass.StaticMethod();,必须使用 IStaticMethod.StaticMethod();。从这个使用上可以看出,这种使用方式局限性很大。作为接口,你没有办法知道你的子类,所以无法实现特定的实现,所以一般是在泛型中使用静态方法。

定义泛型接口,约束T必须实现当前接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface ISerializable<T> where T : ISerializable<T>
{
    static T? Deserialize(string json) => JsonSerializer.Deserialize<T>(json);
}

class Student : ISerializable<Student>
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override string ToString() => $"Id: {Id}, Name: {Name}";
}

var student = ISerializable<Student>.Deserialize("{\"Id\":42,\"Name\":\"Tom\"}");

抽象静态方法允许在接口中声明一个必须在实现类中提供具体实现的静态方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IAbstractStaticMethod
{
    static abstract string Foo();
}

class DemoClass : IAbstractStaticMethod
{
    public static string Foo() {
        return nameof(DemoClass);
    }
}

调用 DemoClass.Foo();

经典用法包括:

  1. 单例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface ISingleton<T> where T : ISingleton<T>
{
    static abstract T Instance { get; }
}

class SingletonClass : ISingleton<SingletonClass>
{
    private static readonly Lazy<SingletonClass> _instanceHolder = new(() => new SingletonClass());
    public static SingletonClass Instance => _instanceHolder.Value;
}
  1. 操作符:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IOperators<T> where T : IOperators<T>
{
    static abstract T operator +(T left, T right);
    static abstract T operator -(T left, T right);
}

class MyNumber : IOperators<MyNumber>
{
    public int Value { get; }

    public MyNumber(int value)
    {
        Value = value;
    }

    public static MyNumber operator +(MyNumber left, MyNumber right)
    {
        return new MyNumber(left.Value + right.Value);
    }

    public static MyNumber operator -(MyNumber left, MyNumber right)
    {
        return new MyNumber(left.Value - right.Value);
    }
}
  1. 工厂模式:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IFactory<T>
{
    static abstract T Create();
}

class ClassWithFactoryMethod : IFactory<ClassToBeCreated>
{
    private ClassWithFactoryMethod() 
    public static ClassToBeCreated Create()
    {
        return new ClassToBeCreated();
    }
}

静态虚方法提供了一种方式,允许在接口中定义一个方法,该方法可以在类中被重写,但不是强制的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface IVirtualStaticMethod
{
    /// <summary>
    /// 一个接口中的静态虚方法(带有默认实现)
    /// </summary>
    static virtual void Foo()
    {
        Console.WriteLine("Foo from interface");
    }
}

class DemoClass : IVirtualStaticMethod
{
    public static void Foo() { // 无法使用 override 关键字
        Console.WriteLine("Foo from class");
    }
}

// 调用
DemoClass.Foo();

// 错误,接口的静态虚方法无法直接通过接口来调用
IVirtualStaticMethod.Foo() // 错误用法

这样看感觉静态虚方法好像并没有什么实际用处,仅仅是给出建议,并不强求实现接口的类必须实现。其实,虽然接口静态虚方法无法直接通过接口来获取,但可以通过泛型标记T来获取。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface ITestInterface
{
    static virtual string TestString1() {
        return "接口中的方法";
    }
}

public interface ITestInterfaceGeneric<T> where T : ITestInterfaceGeneric<T>
{
    static virtual string TestString2() {
        return "泛型接口中的方法2";
    }

    // 这样就可以调用到静态虚方法
    static void TestCallGeneric() {
        Console.WriteLine(T.TestString2());
    }
}

public class A : ITestInterface, ITestInterfaceGeneric<A>
{
    public static string TestString2() {
        return "类A中的方法2";
    }
}

public class B : ITestInterface, ITestInterfaceGeneric<B>
{
    public static string TestString1() {
        return "类B中的方法1";
    }
}

static void TestCallInstance<T>(T t) where T : ITestInterface
{
    // 这样也可以调用到静态虚方法
    Console.WriteLine(T.TestString1());
}

// 依次调用
TestCallInstance(new A());
TestCallInstance(new B());
ITestInterfaceGeneric<A>.TestCallGeneric();
ITestInterfaceGeneric<B>.TestCallGeneric();

这些新特性使得接口在C#中变得更加强大和灵活,为开发者提供了更多的设计选择。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024年10月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# 继承、多态性、抽象和接口详解:从入门到精通
在 C# 中,可以将字段和方法从一个类继承到另一个类。我们将“继承概念”分为两类:
小万哥
2024/01/28
6190
C# 继承、多态性、抽象和接口详解:从入门到精通
设计模式学习(四): 1.简单工厂 (附C#实现)
New 这是一个典型的情况, 我们需要在运行时来实例化一些具体的类. 在需要修改或者扩展的时候我们就需要改这段代码. 一个程序中可能会多次出现类似的代码, 这使得维护和更新非常困难而且容易出错. 通过
solenovex
2018/03/01
5660
设计模式学习(四): 1.简单工厂 (附C#实现)
值得永久收藏的 C# 设计模式套路(二)
在第一篇中,主要写了创造模式相关的几种套路。如果你是刚看到这个文章,建议你先去看看第一篇 传送门。
老王Plus
2021/11/23
3030
Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式
相较于社区其他主流的AOP框架,Dora.Interception在Interceptor提供了完全不同的编程方式。我们并没有为Interceptor定义一个接口,正是因为不需要实现一个预定义的接口,Dora.Interception下的Interceptor定义变得更加自由。除此之外,Interceptor的异步执行是我在设计Dora.Interception之初最为关心的问题,也就是说如果Interceptor应用的目标方法是异步的,Interceptor自身也应该被赋予异步执行的能力。接下来我们就来聊
蒋金楠
2018/03/27
6660
Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式
Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式
相较于社区其他主流的AOP框架,Dora.Interception在Interceptor提供了完全不同的编程方式。我们并没有为Interceptor定义一个接口,正是因为不需要实现一个预定义的接口,Dora.Interception下的Interceptor定义变得更加自由。除此之外,Interceptor的异步执行是我在设计Dora.Interception之初最为关心的问题,也就是说如果Interceptor应用的目标方法是异步的,Interceptor自身也应该被赋予异步执行的能力。接下来我们就来聊聊如果你使用了Dora.Interception,如何定义你的Interceptor。
蒋金楠
2018/09/28
3420
Dora.Interception, 为.NET Core度身打造的AOP框架:不一样的Interceptor定义方式
Java 8 新特性|接口静态方法
Java 8 除了给接口带来了 默认方法之外,还给接口带来了 静态方法。而且,Java 8 中的静态方法还可以有具体的实现。
Java小技巧
2022/05/23
3640
C# OOP
(1). 封装:将一些行为以类为单位进行包裹起来,然后通过类进行调用(如People类),可以利用private、public、protected灵活控制属性的可访问性。
明志德道
2023/10/21
2180
C#  OOP
JDK8新特性总结
Lambda表达式是一个新的语言特性,已经在JDK8中加入。它是一个可以传递的代码块,你也可以把它们当做方法参数。Lambda表达式允许您更紧凑地创建单虚方法接口(称为功能接口)的实例。
后端码匠
2019/09/02
1.2K0
C#: 8.0 & 9.0 常用新特性
在《带你了解C#每个版本新特性》 一文中介绍了,C# 1.0 到 7.0 的不同特性,本文接着介绍在 8.0 和 9.0 中的一些常用新特性。
oec2003
2021/04/30
8960
C#: 8.0 & 9.0 常用新特性
[C#1] 11-接口
接口与继承 CLR规定一个类型只能有一个基类型,这种继承成为单继承; 接口继承是指一个类型继承的是接口中的方法签名,而非方法实现,通常称为实现接口; 接口仅仅是含有一组虚方法的抽象类型,不含有任何实现。CLR允许接口包含静态方法、静态字段、常量、以及静态构造器, 但是CLS兼容的接口类型是不允许有任何静态成员的,因为一些编程语言不能定义或者访问它们。 C#语言就是如此,C#编译器不允许接口中有任何静态成员。 约定接口名称第一个字母是大写的I;接口可以多继承,实际上实现了多个接口的类型允许我们将它的对象看作这
blackheart
2018/01/19
5850
[译] 预览 C# 10 的新东西
本周早些时候(译注:原文发表于5月1日),我关注了 Mads Torgersen[5] 在DotNet SouthWest[6] 大会上的演讲[7],他是微软的 C# 语言的首席设计师。他概述了 C# 10 即将包含的很酷的一些新东西。让我们来快速浏览一下。
zls365
2021/10/19
4300
.NET高级特性-Emit(2)类的定义
在上一篇博文发了一天左右的时间,就收到了博客园许多读者的评论和推荐,非常感谢,我也会及时回复读者的评论。之后我也将继续撰写博文,梳理相关.NET的知识,希望.NET的圈子能越来越大,开发者能了解/深入.NET的本质,将工作做的简单又高效,拒绝重复劳动,拒绝CRUD。
李明成
2020/02/12
1.2K0
C# .NET面试系列二:面向对象
构造函数(Constructor)是一种特殊类型的方法,它在创建类的实例(对象)时被调用,用于初始化对象的状态。构造函数的名称必须与包含它的类的名称相同,并且没有返回类型。
GoodTime
2024/03/07
3533
C# .NET面试系列二:面向对象
【5min+】 巨大的争议?C# 8 中的接口
【五分钟的dotnet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net知识等等。 5min+不是超过5分钟的意思,"+"是知识的增加。so,它是让您花费5分钟以下的时间来提升您的知识储备量。
梁规晓
2020/02/26
5970
C# 多态性
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。
landv
2018/12/28
5930
C#基础知识系列七(base、this、new、override、abstract、virtual、static)
本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base、this、new、override、abstract、virtual以及针对static字段和static构造函数之间的执行问题。
aehyok
2018/08/31
6860
C#基础知识系列七(base、this、new、override、abstract、virtual、static)
C#-面向对象编程、接口、泛型
1 开闭原则:对扩展开放,对修改(old Code)关闭 2 类的单一职责:每个类有且只有一个改变它的原因 3 优先使用组合而非继承: 避免耦合度过高 4 面向接口编程而非面向过程: 定义一个类的时候,先思考对外提供什么功能,定义一个对外的接口 5 依赖倒置: 依赖抽象代码,因为具体实现容易改变 6 接口隔离:尽量定义小而精的接口,类实现多个功能,继承多个接口 7 里式替换:父类可以被子类替换掉 8 迪米特法则 : 类之间数据传递越少越好
祝你万事顺利
2019/05/28
8630
理解C#泛型运作原理
我们都知道泛型在C#的重要性,泛型是OOP语言中三大特征的多态的最重要的体现,几乎泛型撑起了整个.NET框架,在讲泛型之前,我们可以抛出一个问题,我们现在需要一个可扩容的数组类,且满足所有类型,不管是值类型还是引用类型,那么在没有用泛型方法实现,如何实现?
ryzenWzd
2021/03/07
7250
C#基础篇——泛型
在开发编程中,我们经常会遇到功能非常相似的功能模块,只是他们的处理的数据不一样,所以我们会分别采用多个方法来处理不同的数据类型。但是这个时候,我们就会想一个问题,有没有办法实现利用同一个方法来传递不同种类型的参数呢?
zls365
2021/04/23
1.4K0
C#基础篇——泛型
C#高性能开发之类型系统:从C# 7.0 到C# 14的类型系统演进全景
自C# 7.0以来,C#语言在类型系统方面引入了众多新数据类型、类型构造和语言特性,以提升性能、类型安全性和开发效率。本文全面整理了从C# 7.0到C# 14.0(截至2025年4月,C# 14.0为预览版)类型系统的新增内容,包括值元组、Span<T>、ReadOnlySpan<T>、Memory<T>、ReadOnlyMemory<T>、可空引用类型、记录、本机大小整数、记录结构、内联数组,以及其他增强(如只读结构、泛型数学支持)。
AI.NET 极客圈
2025/04/24
760
C#高性能开发之类型系统:从C# 7.0 到C# 14的类型系统演进全景
相关推荐
C# 继承、多态性、抽象和接口详解:从入门到精通
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验